aliasing expressions and identifiers

Marc Schütz via Digitalmars-d digitalmars-d at puremagic.com
Fri May 27 04:50:42 PDT 2016


On Friday, 27 May 2016 at 10:04:14 UTC, Nick Treleaven wrote:
> On Thursday, 26 May 2016 at 08:29:41 UTC, Marc Schütz wrote:
>> To elaborate: neither `scope` nor reference counting can ever 
>> protect you against explicit premature destruction of a 
>> still-referenced owner. But there is a slightly different 
>> problematic scenario:
>>
>> RCArray!int arr = [7];
>> ref r = arr[0];
>> arr = [9];        // this releases the old array
>> r++;              // use after free
>
> This is the same situation. There's nothing special about 
> destroy, it just assigns arr = arr.init. destroy is @safe so in 
> fact it must work with safe RC.

If this is what destroy does, then yes, that's ok. But it is a 
misleading name then, IMO.

> You seem to have ignored my suggestion (which maybe wasn't 
> clear enough) to statically prevent the above from compiling 
> using:
>
> RCArray(T) {
>     ...
>     ref opIndex(size_t) return;
>
> Local refs cannot be assigned from a function returning ref if 
> that function has any parameters marked with the return 
> attribute. If there is no attribute, local refs + function 
> returning ref is OK.

Huh? `return` means that the returned reference is owned by the 
RCArray struct and must therefore not outlive it. If the RCArray 
is a local variable (or parameter), the local ref is always 
declared after it (because it must be initialized immediately), 
and will have a shorter scope than the RCArray. Therefore, such 
an assignment is always accepted.

>
>> But this issue exists even without locale `ref`s:
>>
>> void foo() {
>>     RCArray!int arr = [7];
>>     bar(arr, arr[0]);
>> }
>>
>> void bar(ref RCArray!int arr, ref int r) {
>>     arr = [9];    // this releases the old array
>>     r++;          // use after free
>> }
>
> This is the reason for the @rc DIP.
>
>> It can be solved in one of two ways: Either by making the 
>> owner (`arr`) non-mutable during the existence of the 
>> references, thereby forbidding the call to `bar()` (I would 
>> prefer this one, as it's cleaner and can be used for many more 
>> things, e.g. the byLine problem)
>
> I don't see directly how this affects byLine.front, that does 
> not return a reference.

It returns a reference in the wider sense, namely a slice to a 
private buffer that gets overwritten by each call to `byLine`. 
Currently, DIP25 only applies to `ref`s in the narrow sense, but 
I'm assuming it will be generalized to include pointer, slices, 
class references, AAs and hidden context pointers.

Making the ByLine range constant as long as there's a reference 
to its buffer would prevent surprises like this:

     auto lines = stdin.byLine.array;
     // => all elements of `lines` are the same, should have used 
`byLineCopy`

By the way, there's a theoretical third possibility: 
Force-invalidating the references after the owner has 
(potentially) been mutated. But this would require very advanced 
data flow tracking and is probably impossible to implement in the 
general case.


More information about the Digitalmars-d mailing list