On Thursday, 26 May 2016 at 08:29:41 UTC, Marc Schütz wrote:
On Wednesday, 25 May 2016 at 19:47:06 UTC, Nick Treleaven wrote:
On 24/05/2016 14:48, Nick Treleaven wrote:
@safe unittest
{
RCArray!int arr;
+ arr.length = 1;
ref r = arr[0];
arr.destroy; // refcount drops to zero, arr.impl memory
freed
r++; // writes to unallocated memory
}
Here I think local refs must be prevented from initialization
by return ref (-dip25). The @rc DIP and RCArray would use
return ref. It would be OK to initialize a local ref with a
ref function result that is not return ref.
...
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. 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.
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.