mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
Merge pull request #6090 from WalterBright/add-safe.d
refactor: move safe code to safe.d
This commit is contained in:
commit
2777fdad0e
4 changed files with 184 additions and 146 deletions
152
src/expression.d
152
src/expression.d
|
@ -13,6 +13,7 @@ module ddmd.expression;
|
|||
import core.stdc.stdarg;
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.string;
|
||||
|
||||
import ddmd.access;
|
||||
import ddmd.aggregate;
|
||||
import ddmd.aliasthis;
|
||||
|
@ -59,6 +60,7 @@ import ddmd.root.filename;
|
|||
import ddmd.root.outbuffer;
|
||||
import ddmd.root.rmem;
|
||||
import ddmd.root.rootobject;
|
||||
import ddmd.safe;
|
||||
import ddmd.sideeffect;
|
||||
import ddmd.target;
|
||||
import ddmd.tokens;
|
||||
|
@ -80,71 +82,6 @@ void emplaceExp(T : UnionExp)(T* p, Expression e)
|
|||
memcpy(p, cast(void*)e, e.size);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Check for unsafe access in @safe code:
|
||||
* 1. read overlapped pointers
|
||||
* 2. write misaligned pointers
|
||||
* 3. write overlapped storage classes
|
||||
* Print error if unsafe.
|
||||
* Params:
|
||||
* sc = scope
|
||||
* e = expression to check
|
||||
* readonly = if access is read-only
|
||||
* printmsg = print error message if true
|
||||
* Returns:
|
||||
* true if error
|
||||
*/
|
||||
|
||||
private bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
|
||||
{
|
||||
if (e.op != TOKdotvar)
|
||||
return false;
|
||||
DotVarExp dve = cast(DotVarExp)e;
|
||||
if (VarDeclaration v = dve.var.isVarDeclaration())
|
||||
{
|
||||
if (sc.intypeof || !sc.func || !sc.func.isSafeBypassingInference())
|
||||
return false;
|
||||
|
||||
auto ad = v.toParent2().isAggregateDeclaration();
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
if (v.overlapped && v.type.hasPointers() && sc.func.setUnsafe())
|
||||
{
|
||||
if (printmsg)
|
||||
e.error("field %s.%s cannot access pointers in @safe code that overlap other fields",
|
||||
ad.toChars(), v.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (readonly || !e.type.isMutable())
|
||||
return false;
|
||||
|
||||
if (v.type.hasPointers() && v.type.toBasetype().ty != Tstruct)
|
||||
{
|
||||
if ((ad.type.alignment() < Target.ptrsize ||
|
||||
(v.offset & (Target.ptrsize - 1))) &&
|
||||
sc.func.setUnsafe())
|
||||
{
|
||||
if (printmsg)
|
||||
e.error("field %s.%s cannot modify misaligned pointers in @safe code",
|
||||
ad.toChars(), v.toChars());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (v.overlapUnsafe && sc.func.setUnsafe())
|
||||
{
|
||||
if (printmsg)
|
||||
e.error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
|
||||
ad.toChars(), v.toChars());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* Given var, we need to get the
|
||||
* right 'this' pointer if var is in an outer class, but our
|
||||
|
@ -11306,89 +11243,14 @@ extern (C++) final class CastExp : UnaExp
|
|||
return ex;
|
||||
|
||||
// Check for unsafe casts
|
||||
if (sc.func && !sc.intypeof)
|
||||
if (sc.func && !sc.intypeof &&
|
||||
!isSafeCast(ex, t1b, tob) &&
|
||||
sc.func.setUnsafe())
|
||||
{
|
||||
// Disallow unsafe casts
|
||||
|
||||
// Implicit conversions are always safe
|
||||
if (t1b.implicitConvTo(tob))
|
||||
goto Lsafe;
|
||||
|
||||
if (!tob.hasPointers())
|
||||
goto Lsafe;
|
||||
|
||||
if (tob.ty == Tclass && t1b.ty == Tclass)
|
||||
{
|
||||
ClassDeclaration cdfrom = t1b.isClassHandle();
|
||||
ClassDeclaration cdto = tob.isClassHandle();
|
||||
|
||||
int offset;
|
||||
if (!cdfrom.isBaseOf(cdto, &offset))
|
||||
goto Lunsafe;
|
||||
|
||||
if (cdfrom.isCPPinterface() || cdto.isCPPinterface())
|
||||
goto Lunsafe;
|
||||
|
||||
if (!MODimplicitConv(t1b.mod, tob.mod))
|
||||
goto Lunsafe;
|
||||
goto Lsafe;
|
||||
}
|
||||
|
||||
if (tob.ty == Tarray && t1b.ty == Tsarray) // Bugzilla 12502
|
||||
t1b = t1b.nextOf().arrayOf();
|
||||
|
||||
if (tob.ty == Tarray && t1b.ty == Tarray ||
|
||||
tob.ty == Tpointer && t1b.ty == Tpointer)
|
||||
{
|
||||
Type tobn = tob.nextOf().toBasetype();
|
||||
Type t1bn = t1b.nextOf().toBasetype();
|
||||
|
||||
/* From void[] to anything mutable is unsafe because:
|
||||
* int*[] api;
|
||||
* void[] av = api;
|
||||
* int[] ai = cast(int[]) av;
|
||||
* ai[0] = 7;
|
||||
* *api[0] crash!
|
||||
*/
|
||||
if (t1bn.ty == Tvoid && tobn.isMutable())
|
||||
{
|
||||
if (tob.ty == Tarray && ex.op == TOKarrayliteral)
|
||||
goto Lsafe;
|
||||
goto Lunsafe;
|
||||
}
|
||||
|
||||
// If the struct is opaque we don't know about the struct members then the cast becomes unsafe
|
||||
if (tobn.ty == Tstruct && !(cast(TypeStruct)tobn).sym.members ||
|
||||
t1bn.ty == Tstruct && !(cast(TypeStruct)t1bn).sym.members)
|
||||
goto Lunsafe;
|
||||
|
||||
const t1pointers = t1bn.hasPointers();
|
||||
const topointers = tobn.hasPointers();
|
||||
|
||||
if (t1pointers && !topointers && tobn.isMutable())
|
||||
goto Lunsafe;
|
||||
|
||||
if (!t1pointers && topointers)
|
||||
goto Lunsafe;
|
||||
|
||||
if (!topointers &&
|
||||
tobn.ty != Tfunction && t1bn.ty != Tfunction &&
|
||||
(tob.ty == Tarray || tobn.size() <= t1bn.size()) &&
|
||||
MODimplicitConv(t1bn.mod, tobn.mod))
|
||||
{
|
||||
goto Lsafe;
|
||||
}
|
||||
}
|
||||
|
||||
Lunsafe:
|
||||
if (sc.func.setUnsafe())
|
||||
{
|
||||
error("cast from %s to %s not allowed in safe code", e1.type.toChars(), to.toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
error("cast from %s to %s not allowed in safe code", e1.type.toChars(), to.toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
Lsafe:
|
||||
return ex;
|
||||
}
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ FRONT_SRCS=$(addsuffix .d,access aggregate aliasthis apply argtypes arrayop \
|
|||
globals hdrgen id identifier impcnvtab imphint init inline intrange \
|
||||
json lexer lib link mars mtype nogc nspace opover optimize parse sapply \
|
||||
sideeffect statement staticassert target tokens traits utf visitor \
|
||||
typinf utils statementsem)
|
||||
typinf utils statementsem safe)
|
||||
|
||||
ifeq ($(D_OBJC),1)
|
||||
FRONT_SRCS += objc.d
|
||||
|
|
175
src/safe.d
Normal file
175
src/safe.d
Normal file
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
* Compiler implementation of the
|
||||
* $(LINK2 http://www.dlang.org, D programming language).
|
||||
*
|
||||
* Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(DMDSRC _safe.d)
|
||||
*/
|
||||
|
||||
module ddmd.safe;
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
||||
import ddmd.aggregate;
|
||||
import ddmd.dclass;
|
||||
import ddmd.declaration;
|
||||
import ddmd.dscope;
|
||||
import ddmd.expression;
|
||||
import ddmd.mtype;
|
||||
import ddmd.target;
|
||||
import ddmd.tokens;
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* Check for unsafe access in @safe code:
|
||||
* 1. read overlapped pointers
|
||||
* 2. write misaligned pointers
|
||||
* 3. write overlapped storage classes
|
||||
* Print error if unsafe.
|
||||
* Params:
|
||||
* sc = scope
|
||||
* e = expression to check
|
||||
* readonly = if access is read-only
|
||||
* printmsg = print error message if true
|
||||
* Returns:
|
||||
* true if error
|
||||
*/
|
||||
|
||||
bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
|
||||
{
|
||||
if (e.op != TOKdotvar)
|
||||
return false;
|
||||
DotVarExp dve = cast(DotVarExp)e;
|
||||
if (VarDeclaration v = dve.var.isVarDeclaration())
|
||||
{
|
||||
if (sc.intypeof || !sc.func || !sc.func.isSafeBypassingInference())
|
||||
return false;
|
||||
|
||||
auto ad = v.toParent2().isAggregateDeclaration();
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
if (v.overlapped && v.type.hasPointers() && sc.func.setUnsafe())
|
||||
{
|
||||
if (printmsg)
|
||||
e.error("field %s.%s cannot access pointers in @safe code that overlap other fields",
|
||||
ad.toChars(), v.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (readonly || !e.type.isMutable())
|
||||
return false;
|
||||
|
||||
if (v.type.hasPointers() && v.type.toBasetype().ty != Tstruct)
|
||||
{
|
||||
if ((ad.type.alignment() < Target.ptrsize ||
|
||||
(v.offset & (Target.ptrsize - 1))) &&
|
||||
sc.func.setUnsafe())
|
||||
{
|
||||
if (printmsg)
|
||||
e.error("field %s.%s cannot modify misaligned pointers in @safe code",
|
||||
ad.toChars(), v.toChars());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (v.overlapUnsafe && sc.func.setUnsafe())
|
||||
{
|
||||
if (printmsg)
|
||||
e.error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
|
||||
ad.toChars(), v.toChars());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
* Determine if it is @safe to cast e from tfrom to tto.
|
||||
* Params:
|
||||
* e = expression to be cast
|
||||
* tfrom = type of e
|
||||
* tto = type to cast e to
|
||||
* Returns:
|
||||
* true if @safe
|
||||
*/
|
||||
bool isSafeCast(Expression e, Type tfrom, Type tto)
|
||||
{
|
||||
// Implicit conversions are always safe
|
||||
if (tfrom.implicitConvTo(tto))
|
||||
return true;
|
||||
|
||||
if (!tto.hasPointers())
|
||||
return true;
|
||||
|
||||
auto tfromb = tfrom.toBasetype();
|
||||
auto ttob = tto.toBasetype();
|
||||
|
||||
if (ttob.ty == Tclass && tfrom.ty == Tclass)
|
||||
{
|
||||
ClassDeclaration cdfrom = tfrom.isClassHandle();
|
||||
ClassDeclaration cdto = ttob.isClassHandle();
|
||||
|
||||
int offset;
|
||||
if (!cdfrom.isBaseOf(cdto, &offset))
|
||||
return false;
|
||||
|
||||
if (cdfrom.isCPPinterface() || cdto.isCPPinterface())
|
||||
return false;
|
||||
|
||||
if (!MODimplicitConv(tfrom.mod, ttob.mod))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ttob.ty == Tarray && tfrom.ty == Tsarray) // Bugzilla 12502
|
||||
tfrom = tfrom.nextOf().arrayOf();
|
||||
|
||||
if (ttob.ty == Tarray && tfrom.ty == Tarray ||
|
||||
ttob.ty == Tpointer && tfrom.ty == Tpointer)
|
||||
{
|
||||
Type ttobn = ttob.nextOf().toBasetype();
|
||||
Type tfromn = tfrom.nextOf().toBasetype();
|
||||
|
||||
/* From void[] to anything mutable is unsafe because:
|
||||
* int*[] api;
|
||||
* void[] av = api;
|
||||
* int[] ai = cast(int[]) av;
|
||||
* ai[0] = 7;
|
||||
* *api[0] crash!
|
||||
*/
|
||||
if (tfromn.ty == Tvoid && ttobn.isMutable())
|
||||
{
|
||||
if (ttob.ty == Tarray && e.op == TOKarrayliteral)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the struct is opaque we don't know about the struct members then the cast becomes unsafe
|
||||
if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members ||
|
||||
tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
|
||||
return false;
|
||||
|
||||
const frompointers = tfromn.hasPointers();
|
||||
const topointers = ttobn.hasPointers();
|
||||
|
||||
if (frompointers && !topointers && ttobn.isMutable())
|
||||
return false;
|
||||
|
||||
if (!frompointers && topointers)
|
||||
return false;
|
||||
|
||||
if (!topointers &&
|
||||
ttobn.ty != Tfunction && tfromn.ty != Tfunction &&
|
||||
(ttob.ty == Tarray || ttobn.size() <= tfromn.size()) &&
|
||||
MODimplicitConv(tfromn.mod, ttobn.mod))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -151,6 +151,7 @@ FRONT_SRCS=access.d aggregate.d aliasthis.d apply.d argtypes.d arrayop.d \
|
|||
impcnvtab.d init.d inline.d intrange.d json.d lexer.d lib.d link.d \
|
||||
mars.d mtype.d nogc.d nspace.d objc_stubs.d opover.d optimize.d parse.d \
|
||||
sapply.d sideeffect.d statement.d staticassert.d target.d tokens.d \
|
||||
safe.d \
|
||||
traits.d utf.d utils.d visitor.d libomf.d scanomf.d typinf.d \
|
||||
libmscoff.d scanmscoff.d statementsem.d
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue