The following code will generate an access violation on DMD 2.070
[code]
@safe:
struct Foo(alias Callback)
{
~this() {Callback();}
}
unittest
{
uint stackVar;
void bar() {++stackVar;}
alias FooType = Foo!(bar);
FooType foo = FooType.init;
}
[/code]
[output]
object.Error@(0): Access Violation
----------------
0x00405F46 in @safe void test.__unittestL9_4().bar() at <path>\test.d(12)
0x00405F5D in @safe void test.Foo!(@safe void test.__unittestL9_4().bar()).Foo.__dtor() at <path>\test.d(6)
0x00405F37 in @safe void test.__unittestL9_4() at <path>\test.d(14)
0x00405FB8 in void test.__modtest()
0x0040B635 in int core.runtime.runModuleUnitTests().__foreachbody1(object.ModuleInfo*)
0x004153CF in int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)).__lambda2(immutable(object.ModuleInfo*))
Program exited with code 1
[/output]
Line 12 is the definition of bar().
Line 6 is the destructor of Foo.
Line 14 is the assignment of foo from FooType.init.
Comment #1 by bugzilla — 2016-06-08T07:54:26Z
What's happening is the .init is insufficient to initialize foo, because local structs are also initialized with a runtime dynamic link to the stack frame of the caller. The .init has this field set to null.
Technically, this is not an @safe issue because @safe does not care about null pointer accesses, because null pointer accesses are not memory safety issues.
Semantically, this case is no different from:
@safe void foo()
{
int* p = null;
*p = 3;
}
which will also compile successfully and seg fault at runtime.
If this issue were 'fixed', how would one explain that the pointer init to null issue is legal but the local struct init to null is not? I suspect that the cure would be worse than the problem, so I am going to mark this as wontfix.
----------------------------
The program will run successfully if you let the compiler do the initialization, as in replace:
FooType foo = FooType.init;
with:
FooType foo;