Skip to content

Commit

Permalink
Merge pull request #6172 from WalterBright/fix16589
Browse files Browse the repository at this point in the history
fix Issue 16589 - Taking address of stack variables in @safe code is …
  • Loading branch information
WalterBright committed Oct 7, 2016
2 parents 68c35a6 + 3421336 commit c871b7b
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 12 deletions.
66 changes: 54 additions & 12 deletions src/expression.d
Expand Up @@ -10581,6 +10581,28 @@ extern (C++) final class AddrExp : UnaExp

type = e1.type.pointerTo();

bool checkAddressVar(VarDeclaration v)
{
if (v)
{
if (!v.canTakeAddressOf())
{
error("cannot take address of %s", e1.toChars());
return false;
}
if (sc.func && !sc.intypeof && !v.isDataseg())
{
if (sc.func.setUnsafe())
{
const(char)* p = v.isParameter() ? "parameter" : "local";
error("cannot take address of %s %s in @safe function %s", p, v.toChars(), sc.func.toChars());
return false;
}
}
}
return true;
}

// See if this should really be a delegate
if (e1.op == TOKdotvar)
{
Expand All @@ -10604,26 +10626,36 @@ extern (C++) final class AddrExp : UnaExp
// Look for misaligned pointer in @safe mode
if (checkUnsafeAccess(sc, dve, !type.isMutable(), true))
return new ErrorExp();

if (dve.e1.op == TOKvar && global.params.safe)
{
VarExp ve = cast(VarExp)dve.e1;
VarDeclaration v = ve.var.isVarDeclaration();
if (v)
{
if (!checkAddressVar(v))
return new ErrorExp();
}
}
else if ((dve.e1.op == TOKthis || dve.e1.op == TOKsuper) && global.params.safe)
{
ThisExp ve = cast(ThisExp)dve.e1;
VarDeclaration v = ve.var.isVarDeclaration();
if (v && v.storage_class & STCref)
{
if (!checkAddressVar(v))
return new ErrorExp();
}
}
}
else if (e1.op == TOKvar)
{
VarExp ve = cast(VarExp)e1;
VarDeclaration v = ve.var.isVarDeclaration();
if (v)
{
if (!v.canTakeAddressOf())
{
error("cannot take address of %s", e1.toChars());
if (!checkAddressVar(v))
return new ErrorExp();
}
if (sc.func && !sc.intypeof && !v.isDataseg())
{
if (sc.func.setUnsafe())
{
const(char)* p = v.isParameter() ? "parameter" : "local";
error("cannot take address of %s %s in @safe function %s", p, v.toChars(), sc.func.toChars());
}
}

ve.checkPurity(sc, v);
}
Expand Down Expand Up @@ -10675,6 +10707,16 @@ extern (C++) final class AddrExp : UnaExp
}
}
}
else if ((e1.op == TOKthis || e1.op == TOKsuper) && global.params.safe)
{
ThisExp ve = cast(ThisExp)e1;
VarDeclaration v = ve.var.isVarDeclaration();
if (v)
{
if (!checkAddressVar(v))
return new ErrorExp();
}
}
else if (e1.op == TOKcall)
{
CallExp ce = cast(CallExp)e1;
Expand Down
65 changes: 65 additions & 0 deletions test/fail_compilation/test16589.d
@@ -0,0 +1,65 @@
/* PERMUTE_ARGS:
REQUIRED_ARGS: -transition=safe
TEST_OUTPUT:
---
fail_compilation/test16589.d(26): Error: cannot take address of parameter this in @safe function access1
fail_compilation/test16589.d(31): Error: cannot take address of parameter this in @safe function access2
fail_compilation/test16589.d(37): Error: cannot take address of parameter s in @safe function access3
fail_compilation/test16589.d(42): Error: cannot take address of parameter s in @safe function access4
fail_compilation/test16589.d(47): Error: cannot take address of parameter s in @safe function access5
fail_compilation/test16589.d(52): Error: cannot take address of parameter s in @safe function access6
---
*/





// https://issues.dlang.org/show_bug.cgi?id=16589

struct S
{
int data;

@safe int* access1()
{
return &data;
}

@safe S* access2()
{
return &this;
}
}

@safe int* access3(ref S s)
{
return &s.data;
}

@safe S* access4(ref S s)
{
return &s;
}

@safe int* access5(S s)
{
return &s.data;
}

@safe S* access6(S s)
{
return &s;
}

class C
{
int data;

@safe int* access7()
{
return &data;
}
}


0 comments on commit c871b7b

Please sign in to comment.