Bug 13468 – Wrong code when comparing class reference with typeof(null)

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-09-13T16:48:00Z
Last change time
2015-02-18T03:39:28Z
Keywords
pull, wrong-code
Assigned to
nobody
Creator
ryan

Attachments

IDFilenameSummaryContent-TypeSize
1427canfind.dtest file, should segfaulttext/x-dsrc358

Comments

Comment #0 by ryan — 2014-09-13T16:48:25Z
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.
Comment #7 by yebblies — 2014-11-11T10:08:20Z
Pull to essentially treat typeof(null) == class as typeof(null) is class. https://github.com/D-Programming-Language/dmd/pull/4135
Comment #8 by github-bugzilla — 2014-11-12T23:16:09Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/6d0a31ed73686e5e2908236c03586b368e0e5d02 Fix Issue 13468 - Wrong code when comparing class reference with typeof(null) https://github.com/D-Programming-Language/dmd/commit/b2c0d4a7d9b0b969fb186f15cb4178c88dd02564 Merge pull request #4135 from yebblies/issue13468 Issue 13468 - Wrong code when comparing class reference with typeof(null)
Comment #9 by github-bugzilla — 2015-02-18T03:39:28Z
Commits pushed to 2.067 at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/6d0a31ed73686e5e2908236c03586b368e0e5d02 Fix Issue 13468 - Wrong code when comparing class reference with typeof(null) https://github.com/D-Programming-Language/dmd/commit/b2c0d4a7d9b0b969fb186f15cb4178c88dd02564 Merge pull request #4135 from yebblies/issue13468