Consider this code:
class Foo
{
this(ref int _i) { dg = (){return _i;} }
ref int delegate() dg;
}
immutable Foo f;
int notShared;
shared static this()
{
f = new Foo(notShared);
}
Since f is implicitly shared, it provides access to notShared from the main thread's local storage without protections (locks or immutable guarantees). All one has to do is call the delegate dg.
I think in order to prevent this from accidentally happening, you should be required to cast to either shared or immutable a delegate or anything that contains a delegate (directly or indirectly).
The same issue occurs with shared.
This is related to bug 6741
Comment #1 by maxhaton — 2021-01-24T06:14:00Z
Still a problem BUT @safe does catch the problem in it.
https://d.godbolt.org/z/Px5aTM
------------------
import std.algorithm;
import std.stdio;
import std.traits;
class Foo //@safe can catch the bug with ref
{
immutable this(ref int _i)
{
dg = (){++_i;};
}
void delegate() dg;
}
immutable Foo f;
int notShared;
shared static this()
{
f = new immutable Foo(notShared);
}
void sharedInc(immutable Foo x)
{
x.dg();
}
void main()
{
import std.stdio;
import std;
f.dg();
f.dg();
f.dg();
auto file1Task = task!sharedInc(f);
file1Task.executeInNewThread();
// Read bar.txt in parallel.
sharedInc(f);
// Get the results of reading foo.txt.
file1Task.yieldForce;
}
Comment #2 by schveiguy — 2021-01-24T16:25:34Z
The ref is incidental.
Using pointers it compiles:
class Foo
{
this(int *_i) immutable @safe { dg = (){return _i;}; }
int* delegate() dg;
}
immutable Foo f;
int notShared;
shared static this()
{
f = new immutable Foo(¬Shared);
}
Comment #3 by robert.schadek — 2024-12-13T17:56:34Z