From 34213361ec3cd13485db7eb4044e93b85178397c Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 4 Oct 2016 03:12:26 -0700 Subject: [PATCH] fix Issue 16589 - Taking address of stack variables in @safe code is allowed in some cases --- src/expression.d | 66 +++++++++++++++++++++++++------ test/fail_compilation/test16589.d | 65 ++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 test/fail_compilation/test16589.d diff --git a/src/expression.d b/src/expression.d index 8a2565527973..cb2aceef711c 100644 --- a/src/expression.d +++ b/src/expression.d @@ -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) { @@ -10604,6 +10626,27 @@ 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) { @@ -10611,19 +10654,8 @@ extern (C++) final class AddrExp : UnaExp 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); } @@ -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; diff --git a/test/fail_compilation/test16589.d b/test/fail_compilation/test16589.d new file mode 100644 index 000000000000..9b94e3bebc49 --- /dev/null +++ b/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; + } +} + +