On Monday, 4 September 2017 at 17:58:41 UTC, Johan Engelen wrote:
On Monday, 4 September 2017 at 09:47:12 UTC, Moritz Maxeiner wrote:
On Monday, 4 September 2017 at 09:15:30 UTC, ag0aep6g wrote:
On 09/04/2017 06:10 AM, Moritz Maxeiner wrote:
Indeed, but it also means that - other than null dereferencing - pointer issues can by made into reference issues my dereferencing a pointer and passing that into a function that takes that parameter by reference.

Why "other than null dereferencing"? You can dereference a null pointer and pass it in a ref parameter. That doesn't crash at the call site, but only when the callee accesses the parameter:

[...]

Because I was ignorant and apparently wrong, thanks for the correction. Still, though, this is surprising to me, because this means taking the address of a parameter passed by reference (which is in your case is typed as an existing int) can be null. Is this documented somewhere (couldn't find it in the spec and it seems like a bug to me)?

LDC treats passing `null` to a reference parameter as UB.
It doesn't matter when the program crashes after passing null to ref, exactly because it is UB.

Ok, that's good to know, though it'd be nice for this to be defined somewhere in the language spec.

Because the caller has to do the dereferencing (semantically) you only have to do the null-check in the caller, and not in callee. This removes a ton of manual null-ptr checks from the code, and enables more optimizations too.

Indeed, which is why I currently think the spec should state that this isn't UB, but has to crash at the call site.

For class parameters, they are pointers not references, as in: it is _not_ UB to pass-in `null`. Very unfortunate, because it necessitates null-ptr checks everywhere in the code, and hurts performance due to missed optimization opportunities.

Well, technically they are "class references". In any case, they don't require injecting null checks from the compiler in general, as using them in any way will be a null dereference (which the hardware&OS are required to turn into a crash).


(The spec requires crashing on null dereferencing, but this spec bit is ignored by DMD and LDC, I assume in GDC too. Crashing on `null` dereferencing requires a null-check on every dereferencing through an unchecked pointer, because 0 might be a valid memory access, and also because ptr->someDataField is not going to lookup address 0, but 0+offsetof(someDataField) instead, e.g. potentially addressing a valid low address at 1000000, say.)

It's not implemented as compiler checks because the "actual" requirement is "the platform has to crash on null dereference" (see the discussion in/around [1]). Essentially: "if your platform doesn't crash on null dereference, don't use D on it (at the very least not @safe D)". The issue concerning turning a pointer into a reference parameter is that when reading the code it looks like the dereference is happening at the call site, while the resulting compiled executable will actually perform the (null) dereference inside the function on use of the reference parameter. That is why I think the null check should be injected at the call site, because depending on platform support for the crash will may yield the wrong result (if the reference parameter isn't actually used in the function, it won't crash, even though it *should*).

[1] https://forum.dlang.org/post/udkdqogtrvanhbotd...@forum.dlang.org

Reply via email to