C `restrict` keyword in D

Moritz Maxeiner via Digitalmars-d digitalmars-d at puremagic.com
Mon Sep 4 14:23:50 PDT 2017


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/udkdqogtrvanhbotdoik@forum.dlang.org


More information about the Digitalmars-d mailing list