Created attachment 1427
test file, should segfault
I would like to check if any entries in an array of reference types are null.
If you call canFind(null) on an array of a user-defined class, it segfaults.
However, it seems to work with other reference types like string.
Comment #1 by hsteoh — 2014-10-02T04:31:22Z
Found the cause of the bug. The problem is that when comparing two class references, the default predicate attempts to compare two class references with ==, which appears to dereference a NULL and cause a segfault. If "a is b" is used as predicate instead, there is no crash. Next is to find out why == doesn't handle null pointers correctly...
Comment #2 by hsteoh — 2014-10-02T04:36:03Z
Actually it's quite simple. The expression a == b, in the case of classes, is lowered into a.opEquals(b). Since a is null when find/canFind gets to a null element in the array, opEquals is invoked with a null this pointer, with disastrous consequences.
Comment #3 by hsteoh — 2014-10-02T17:07:04Z
Workaround:
Instead of using the default predicate "a==b" with null (i.e., effectively "a == null"), use this instead:
if (canFind!"a is null"(b)) { ... }
Comment #4 by hsteoh — 2014-10-02T17:08:25Z
Alternate syntax:
if (canFind!((a) => a is null)(b)) { ... }
Comment #5 by hsteoh — 2014-10-02T17:24:24Z
Apparently I made a total fool of myself. The *real* reason for the bug is not a.opEquals(b), but is caused by using == to compare a class reference to an instance of typeof(null).
Specifically, this code works:
----------
class C { }
bool fun(C e, C needle)
{
return (e == needle);
}
void main()
{
fun(null, null);
}
----------
But this code segfaults:
----------
class C { }
bool fun(C e, typeof(null) needle)
{
return (e == needle);
}
void main()
{
fun(null, null);
}
----------
The only difference is that the segfaulting case takes `typeof(null)` as parameter. Comparing class references with null is actually OK; what's *not* OK is comparing them with an instance of typeof(null). I think this is a compiler bug.
Comment #6 by hsteoh — 2014-10-02T17:56:21Z
Looking at the disassembly, in the first (working) case, Object.opEquals() is called directly. In the second (segfaulting) case, it appears to be doing a lookup of the vtable (or perhaps typeinfo?) of either C or typeof(null) and dereferencing it without checking for null.