Comment #0 by matti.niemenmaa+dbugzilla — 2008-02-27T16:10:50Z
import std.stdio;
void main() {
writefln(&null[42]);
}
The above prints "002A" - i.e. the hexadecimal representation of 42, the value used to index null.
This is, I'm fairly certain, unspecified behaviour, but I think you'd be hard pressed to argue that this makes sense in any way. I'm marking this as "accepts-invalid" but also as "trivial" since I honestly hope that nobody else has ever dreamed of doing something like this. :-)
The issue is essentially: why does null[x] return a void type, and why is taking its address a valid operation? In addition, why is indexing null valid in the first place? Trying the same with [][x] results in out-of-bounds errors at compile time.
Note that this works even at runtime, for any value of x.
Comment #1 by shro8822 — 2008-02-27T17:11:13Z
&null[47] -> &(null[47]) -> (null + 47) -> (0 + 47) -> 47
Why is that unexpected? What should it do? if that null is not a literal the only way to check would be to do a read but that can have problems of it's own.
also; null is a pointer. all pointers are indexable. -> null is indexable*
also it it's a way to avoid a cast for constant pointers. (Not saying it's a good idea...)
void* HW_ptr = &null[0xf000];
* the phrasing is so classic I couldn't resist the last bit.
Comment #2 by matti.niemenmaa+dbugzilla — 2008-02-28T00:54:16Z
I don't think it makes sense for void pointers to be indexable, just like they aren't in C.
For that matter, I think indexing pointer constants in general deserves a warning, at least. For the case of null, it should be an error: why is indexing cast(int[])null an array bounds error, but indexing null as a pointer isn't? In both cases, you know there are no valid elements there - that's the definition of the null pointer.
You'll note that the results are unpredictable: &null[420] is 420, but &(cast(int*)null)[420] is 1680 - that's int.sizeof * 420. And similarly, for a long, you get 3360.
Comment #3 by matti.niemenmaa+dbugzilla — 2008-02-28T01:04:02Z
Hmm, no: the more I think about this the more I think I'm wrong. I shouldn't file bugs at midnight.
I'll leave this as an enhancement request for a warning on dereferencing void pointers.
Comment #4 by braddr — 2008-02-28T01:28:50Z
Um.. at no point in this code has anything been dereferenced. The only thing occurring here is pointer math (against 0, but still just math). Further, it actually _is_ legal in both c and c++. In fact, the offsetof macro is built around that capability:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
Comment #5 by matti.niemenmaa+dbugzilla — 2008-02-28T08:51:02Z
Which is why I said I was wrong. I realize that.
However, I do think there's a dereference going on - even if it's undone by the & to the point that the dereference isn't in the resulting binary. "& (null[x])" is "& *(null + x)" which means that, essentially, "null + x" is being dereferenced.
Your code is different: that's not a void pointer, it's a type-casted null pointer.
GCC gives a "warning: dereferencing 'void *' pointer" for the following C code:
#include <stdlib.h>
int main() {
return (int)&NULL[42];
}
Which is all I ask for. Feel free to mark as WONTFIX if you think that's not going to happen.
Comment #6 by bugzilla — 2008-02-28T22:40:01Z
I don't agree there's a dereference going on unless the result of a folded expression actually does a dereference. At best, it is just an intermediate state in a calculation. Since it's a difference of opinion, I'll just mark it as 'wontfix'.