mirror of
https://github.com/dlang/dmd.git
synced 2025-04-28 22:20:37 +03:00
refactor: move safe code to safe.d
This commit is contained in:
parent
e9594ecaaa
commit
d77a21dd24
4 changed files with 184 additions and 146 deletions
148
src/expression.d
148
src/expression.d
|
@ -13,6 +13,7 @@ module ddmd.expression;
|
||||||
import core.stdc.stdarg;
|
import core.stdc.stdarg;
|
||||||
import core.stdc.stdio;
|
import core.stdc.stdio;
|
||||||
import core.stdc.string;
|
import core.stdc.string;
|
||||||
|
|
||||||
import ddmd.access;
|
import ddmd.access;
|
||||||
import ddmd.aggregate;
|
import ddmd.aggregate;
|
||||||
import ddmd.aliasthis;
|
import ddmd.aliasthis;
|
||||||
|
@ -59,6 +60,7 @@ import ddmd.root.filename;
|
||||||
import ddmd.root.outbuffer;
|
import ddmd.root.outbuffer;
|
||||||
import ddmd.root.rmem;
|
import ddmd.root.rmem;
|
||||||
import ddmd.root.rootobject;
|
import ddmd.root.rootobject;
|
||||||
|
import ddmd.safe;
|
||||||
import ddmd.sideeffect;
|
import ddmd.sideeffect;
|
||||||
import ddmd.target;
|
import ddmd.target;
|
||||||
import ddmd.tokens;
|
import ddmd.tokens;
|
||||||
|
@ -80,71 +82,6 @@ void emplaceExp(T : UnionExp)(T* p, Expression e)
|
||||||
memcpy(p, cast(void*)e, e.size);
|
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
|
* Given var, we need to get the
|
||||||
* right 'this' pointer if var is in an outer class, but our
|
* right 'this' pointer if var is in an outer class, but our
|
||||||
|
@ -11299,89 +11236,14 @@ extern (C++) final class CastExp : UnaExp
|
||||||
return ex;
|
return ex;
|
||||||
|
|
||||||
// Check for unsafe casts
|
// Check for unsafe casts
|
||||||
if (sc.func && !sc.intypeof)
|
if (sc.func && !sc.intypeof &&
|
||||||
{
|
!isSafeCast(ex, t1b, tob) &&
|
||||||
// Disallow unsafe casts
|
sc.func.setUnsafe())
|
||||||
|
|
||||||
// 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());
|
error("cast from %s to %s not allowed in safe code", e1.type.toChars(), to.toChars());
|
||||||
return new ErrorExp();
|
return new ErrorExp();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Lsafe:
|
|
||||||
return ex;
|
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 \
|
globals hdrgen id identifier impcnvtab imphint init inline intrange \
|
||||||
json lexer lib link mars mtype nogc nspace opover optimize parse sapply \
|
json lexer lib link mars mtype nogc nspace opover optimize parse sapply \
|
||||||
sideeffect statement staticassert target tokens traits utf visitor \
|
sideeffect statement staticassert target tokens traits utf visitor \
|
||||||
typinf utils statementsem)
|
typinf utils statementsem safe)
|
||||||
|
|
||||||
ifeq ($(D_OBJC),1)
|
ifeq ($(D_OBJC),1)
|
||||||
FRONT_SRCS += objc.d
|
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 \
|
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 \
|
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 \
|
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 \
|
traits.d utf.d utils.d visitor.d libomf.d scanomf.d typinf.d \
|
||||||
libmscoff.d scanmscoff.d statementsem.d
|
libmscoff.d scanmscoff.d statementsem.d
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue