diff --git a/src/expression.d b/src/expression.d index 2b91dfa5ec80..a79d6051673b 100644 --- a/src/expression.d +++ b/src/expression.d @@ -11244,6 +11244,17 @@ extern (C++) final class CastExp : UnaExp { 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() && ex.op != TOKarrayliteral) + goto Lunsafe; + if (!tobn.hasPointers() && MODimplicitConv(t1bn.mod, tobn.mod)) goto Lsafe; } @@ -11251,6 +11262,17 @@ extern (C++) final class CastExp : UnaExp { Type tobn = tob.nextOf().toBasetype(); Type t1bn = t1b.nextOf().toBasetype(); + + /* From void* to anything mutable is unsafe because: + * int** ppi; + * void* pv = ppi; + * int* pi = cast(int*) pv; + * *pi = 7; + * **ppi crash! + */ + if (t1bn.ty == Tvoid && tobn.isMutable()) + goto Lunsafe; + // If the struct is opaque we don't know about the struct members and the cast becomes unsafe bool sfwrd = tobn.ty == Tstruct && !(cast(TypeStruct)tobn).sym.members || t1bn.ty == Tstruct && !(cast(TypeStruct)t1bn).sym.members; diff --git a/test/fail_compilation/test15672.d b/test/fail_compilation/test15672.d new file mode 100644 index 000000000000..19b5bf1c2d17 --- /dev/null +++ b/test/fail_compilation/test15672.d @@ -0,0 +1,38 @@ +/* + * TEST_OUTPUT: +--- +fail_compilation/test15672.d(15): Error: cast from void[] to byte[] not allowed in safe code +fail_compilation/test15672.d(25): Error: cast from void* to byte* not allowed in safe code +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=15672 + +alias byte T; +alias const(byte) CT; + +@safe T[] test1(void[] a) +{ + return cast(T[])a; +} + +@safe CT[] test2(void[] a) +{ + return cast(CT[])a; +} + +@safe T* test3(void* a) +{ + return cast(T*)a; +} + +@safe CT* test4(void* a) +{ + return cast(CT*)a; +} + +@safe T[] test5() +{ + return cast(T[])[]; +} + + diff --git a/test/runnable/testsafe.d b/test/runnable/testsafe.d index 868fb602bd33..49a1b556759c 100644 --- a/test/runnable/testsafe.d +++ b/test/runnable/testsafe.d @@ -12,7 +12,7 @@ void pointercast() static assert(!__traits(compiles, cast(int*)b)); static assert(!__traits(compiles, cast(int*)b)); static assert(!__traits(compiles, cast(short*)b)); - static assert( __traits(compiles, cast(byte*)b)); + static assert(!__traits(compiles, cast(byte*)b)); static assert( __traits(compiles, cast(short*)a)); static assert( __traits(compiles, cast(byte*)a)); } @@ -311,7 +311,7 @@ void arraycast() int[] x; void[] y = x; static assert( __traits(compiles, cast(void[])x)); - static assert( __traits(compiles, cast(int[])y)); + static assert(!__traits(compiles, cast(int[])y)); static assert(!__traits(compiles, cast(int*[])y)); static assert(!__traits(compiles, cast(void[][])y));