[Dlang-internal] DIP1000 discussion and testing

Martin Nowak via Dlang-internal dlang-internal at puremagic.com
Fri Oct 21 03:11:28 PDT 2016


On Thursday, 20 October 2016 at 09:00:02 UTC, Walter Bright wrote:
>> I read that RC `opAssign` and `destroy` would remain unsafe 
>> b/c destroying the
>> owner might leave a dangling ref parameter in `fun(ref RCS rc, 
>> ref int ri)`.
>> It seems that unsafe assignment/destruction of RCs would be 
>> very limiting.
>> Do we at least have an idea how to tackle this problem? In the 
>> RCClass idea an
>> additional addRef/decRef call was proposed.
>> Also see 
>> https://github.com/dlang/DIPs/pull/35#issuecomment-252345548.
>
> The solution to that has been proposed and forgotten a couple 
> of times. It is to have the compiler insert code to 
> preemptively increment the reference count, then reassigning 
> the RC object will not invalidate references to its internals. 
> This is beyond the scope of DIP1000, though. DIP1000 is 
> necessary for memory safety even without reference counting.

Thought a bit more about this.
The essence of the problem is a simple pointer aliasing problem, 
namely calling
     void dangling(ref A a, ref B b)
is unsafe if A is a "container" that could own a B.
This does not only apply to RC but also things like arrays with 
deterministic MM, unions/variants (changing type of b's pointee), 
or implementations of Nullable/Optional using heap allocated 
memory.

Fortunately any pointer aliasing through untyped memory/pointers 
in A (ubyte[], void*) can only result in a dangling b pointer, if 
doing unsafe operations on a (or incorrectly marked @trusted 
ones).
For pointer aliasing through typed fields of A, the compiler can 
detect a possible aliasing and mark the function call as unsafe.
That would allow operations on a that could free Bs to be 
@trustable.

This aliasing problem seems only slightly related to scope/escape 
analysis.
A container using scope in a @safe manner, should only escape 
scoped references.
So the statement of the problem is actually
   void dangling(ref A a, scope ref B b).

Copying a before the call couldn't solve all those problems, e.g. 
Unique isn't copyable, a union/variant could be in a reference 
type field of A.

But it seems that we can detect all such unsafe function calls 
and the problem only scratches on scope b/c we want to know 
whether the lifetime of b might be limited attached to a. So 
seems indeed fair enough to leave this aside for now.

What would be the plan for RC.opAssign? Making it @trusted after 
DIP1000 and implementing the aliasing detection later, @trusted 
opAssign but conservatively @unsafe any call with multiple 
references (at least one of which being scoped), or @system 
opAssign and changing it to @trusted later?

It seems that the aliasing detect wouldn't be too hard to 
implememt (even implementable as druntime template similar to 
std.traits.hasAliasing). Am I right that conservatively detecting 
the aliasing would allow a slightly limited subset of @safe RC 
usage?
If so going w/ @trusted RC.opAssign and the aliasing detection 
seems like a good milestone for 2.073.


More information about the Dlang-internal mailing list