Comment #0 by victor.v.carvalho — 2011-06-12T21:04:21Z
Created attachment 996
testcase
See the attached test case. Running it causes a segfault on glibc.
Comment #1 by lovelydear — 2012-04-24T07:56:49Z
The following works correctly:
import std.stdio;
import std.container;
int main() {
alias Array!int Arr1D;
alias Array!Arr1D Arr2D;
auto arr1D = Arr1D();
auto arr2D = Arr2D();
writefln("arr1D %s of size = %d", arr1D, arr1D.length());
arr1D.insert(1);
arr1D.insert(2);
writefln("arr1D %s of size = %d", arr1D[0], arr1D.length());
arr2D.insert(arr1D);
writefln("arr2D %s of size = %d", arr2D, arr2D.length());
writeln(arr2D[0][0], arr2D[0][1]);
return 0;
}
It produces the output:
PS E:\DigitalMars\dmd2\samples> rdmd a.d
arr1D Array!(int)(RefCounted!(Payload,cast(RefCountedAutoInitialize)0)(_RefCounted(null))) of size = 0
arr1D 1 of size = 2
arr2D Array!(Array!(int))(RefCounted!(Payload,cast(RefCountedAutoInitialize)0)(_RefCounted(A623F0))) of size = 1
12
PS E:\DigitalMars\dmd2\samples>
However inserting ints in arr1D *after* having inserted it in arr2D produces access violations:
import std.stdio;
import std.container;
int main() {
alias Array!int Arr1D;
alias Array!Arr1D Arr2D;
auto arr1D = Arr1D();
auto arr2D = Arr2D();
arr2D.insert(arr1D);
writefln("arr2D %s of size %d", arr2D[0], arr2D.length());
arr2D[0].insert(1);
arr2D[0].insert(2);
writefln("array size after insert: %d", arr2D[0].length());
//writeln(arr2D[0][0], arr2D[0][1]);
return 0;
}
produces:
PS E:\DigitalMars\dmd2\samples> rdmd bug.d
arr2D Array!(int)(RefCounted!(Payload,cast(RefCountedAutoInitialize)0)(_RefCounted(null))) of size 1
array size after insert: 0
PS E:\DigitalMars\dmd2\samples>
It seems that the reason is, as long as arr1D has no elements inserted via insert, it's not allocated and arr2D[0] is null.
See also issue 7901.
Comment #2 by lovelydear — 2012-04-24T09:05:54Z
*** Issue 7901 has been marked as a duplicate of this issue. ***
Comment #3 by xammy — 2012-07-18T03:14:20Z
The reason for the failure is that for
arr2D[0].insert(1);
the opIndex() method is invoked which returns by value. In theory this is okay since the array is stored by reference and the returned value contains a reference to the payload data of the inner array.
What happens here is that arr2D[0] is uninitialized (the pointer to the RefCounted object is null) and this guy is returned. It is then changed (the insert method initializes the temporary and creates the ref-counted object with the inserted content).
One way to resolve this is to make opIndex return a reference. Or is there an alternative?
Comment #4 by christophe.travert — 2012-07-18T06:46:14Z
(In reply to comment #3)
> The reason for the failure is that for
>
> arr2D[0].insert(1);
>
> the opIndex() method is invoked which returns by value. In theory this is okay
> since the array is stored by reference and the returned value contains a
> reference to the payload data of the inner array.
>
> What happens here is that arr2D[0] is uninitialized (the pointer to the
> RefCounted object is null) and this guy is returned. It is then changed (the
> insert method initializes the temporary and creates the ref-counted object with
> the inserted content).
>
> One way to resolve this is to make opIndex return a reference. Or is there an
> alternative?
I think both should be corrected:
- uninitialised Arrays do not behave as reference values: you can copy them, change the copy, and this does not affect the original. This breaks the intended 'reference value' behavior. The cost of creating a payload for each empty Array may be compensated by not having to check the payload is initialised in each of Array's methods.
- opIndex should return a reference. Any struct with a non-const method will suffer the same problem when 'array[i].method' is called: the method is called on a copy of the contained data.
Note that Array!bool cannot return a reference to a bool, and can't be corrected the same way. I think this is not a problem, but I may miss something.
Comment #5 by andrei — 2013-03-04T15:24:10Z
Works now, probably has been fixed along with other bugs. Feel free to reopen if I missed something.