Bug 2632 – Setting length on invalid arrays causes assertion failure with a debug runtime
Status
RESOLVED
Resolution
INVALID
Severity
major
Priority
P2
Component
dlang.org
Product
D
Version
D1 (retired)
Platform
All
OS
All
Creation time
2009-01-29T11:11:00Z
Last change time
2014-03-01T00:36:17Z
Keywords
spec
Assigned to
nobody
Creator
matti.niemenmaa+dbugzilla
Comments
Comment #0 by matti.niemenmaa+dbugzilla — 2009-01-29T11:11:48Z
Both of the below test cases work unless compiled against a debug runtime.
Test case 1:
void main() {
int[] a = (cast(int*)null)[0..1];
a.length = 1;
assert (a.length == 1);
assert (a[0] == 0);
}
Test case 2:
union Union {
int i;
ubyte[] a;
}
void main() {
Union u;
u.i = 10;
u.a.length = 1;
assert (u.a.length == 1);
assert (u.a[0] == 1);
}
The problematic assertion is assert(!p.length || p.data). It occurs in three functions:
- _d_delarray
- _d_arraysetlengthT
- _d_arraysetlengthiT
The second one of the above is triggered by the given test cases. It'd be easy to come up with ones that trigger the other two as well.
This behaviour doesn't seem to be specified, so I'm not completely sure whether this should be fixed or not. I have two arguments in favour of removing the assertions:
1. They're only sanity checks: they don't actually matter for behaviour. Code which trips the asserts on a debug runtime runs fine on a release runtime. Nothing actually expects the assertions to succeed.
2. Code which relies on such behaviour actually exists: test case 2 was reduced from tango.text.Regex.
In Phobos, the functions are in phobos/internal/gc/gc.d; in Tango, they can be found in tango/lib/compiler/{dmd,gdc}/lifetime.d; in LDC, they're in runtime/internal/lifetime.d. This issue affects all of them.
Comment #1 by matti.niemenmaa+dbugzilla — 2009-02-08T10:33:28Z
I'm moving this to www.digitalmars.com and adding the 'spec' keyword since it seems that there's absolutely nothing written down about this possibility. I believe this needs to be clarified. If the answer indicates that Phobos should change, I'll file a separate bug for that.
The basic issue is, what operations, if any, are allowed on dynamic arrays which are in an invalid state, i.e. have a nonzero length but a null pointer? (I suppose the converse—nonnull pointer but zero length—is fine.) "Implementation defined" is a fine answer as long as it's actually specified.
Associative arrays don't have this problem since their ABI says that they're just a pointer to an implementation defined type.
Comment #2 by bugzilla — 2012-01-22T22:11:06Z
I think both cases are clearly undefined behavior. The first uses a cast to bypass checks in order to create an array of elements that don't exist, the second uses a union to achieve the same.
I don't think the spec needs to be changed to reflect that using unions to manipulate things under the hood, and using forcible casts, mean you're on your own.