Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You are conflating tha language capability with the hardware capability. C/C++ do not place restrictions on dereferencing the 0th address. Consider the following stub:

  /* -O2  -std=c23 -Wall -fno-inline-functions */
  int *ptr0 = 0;
  int *ptr0p = (int *)0;

  int
  main ()
  {
      return *ptr0 | *ptr0p;
  }
Head over to godbolt, compile it, and check the code. Zero compilation warnings, and the compiler duly obliges to generate the code that accesses a memory cell at the address 0x0 and all architectures that godbolt supports (ARM, RISC-V, SPARC64, POWER64, TI, S390 and others – with no exceptions).

So if you run that code on a system before the MMU is activated or on a system without a MMU, «main» will return 0 on all systems[0] (if the memory is initialised with zeroes). You do have a point that some embedded systems[1] may have device registers mapped at 0, but that bears no relevance on the generated code – it will still attempt to read the 0th address.

You can also test the generated code in QEMU on an architecture of your choice in the «bare metal mode» (i.e. memory protection off) and observe that a read from 0 will give you 0 if the first memory page is filled with 0s.

> More info at https://stackoverflow.com/questions/63790813/allocating-addr...

You are most assuredly conflating a pointer to 0 dereferencing with the memory protection/virtual memory management system, and the explanation is in the first answer. It is Linux that implements a kernel-level check in mmap(2) on the address to mmap into, not the hardware. It is a Linux-specific quirk, and other UNIXes will allow the mmap to 0 to proceed but reading from 0 will still yield a SIGSEGV due to memory protection being in use.

> MMU is not the only way memory becomes magic. In fact, it's probably the LEAST of the magic memory mapping that can happen.

MMU is not magic. It is a simple and very efficient design that works in concert with the microarchitecture it has been implemented for – CPU traps, memory page descriptors and tables.

> I mean… you're just wrong. I'm not conflating unrelated things. I'm correcting multiple unrelated mis-statements you made.

Respectfully, so far I am yet to see a single compelling argument or tangible piece of evidence to support the claims you have espoused. I have provided a few very concrete and specific examples as supporting evidence, but I am not seeing the same on your side.

[0] The only exception that does not initialiase memory with zeroes that I am aware of is AIX (but not POWER/PowerPC that it runs on!) – the AIX VMM initialises a new memory page upon allocation with 0xdeadbeef to make unintialised pointers forcefully crash the process. Linux, *BSD's running on POWER/PowerPC do not do it, it is an AIX specific quirk.

[1] Again, embedded may have a nuance (subject to a specific hardware* implementation) as it is a commonplace in embedded systems to not* have a contiguous memory space and have holes in it, including the zeroeth address. It does not preclude the generated code to attempt to access 0, though, if the hardware supports it.



Oh, it's too late to edit my comment, but one more thing:

> You are conflating tha language capability with the hardware capability

No. I'm talking about the C language and the abstract machine that it defines. I'm very much NOT talking about specific hardware, unlike when you bring up MMU and other irrelevant specific hardware capability.

Because specific hardware capability is not part of the language.


One last thing. If you think reading and writing to "address zero" is perfectly fine in C, then I'm curious what your explanation is of GCC removing this null pointer check: https://godbolt.org/z/PjYzqKxs4

It's not a GCC bug.


> C/C++ do not place restrictions on dereferencing the 0th address.

It doesn't. Because it doesn't consider 0th address special. Null pointer though, is special. And it's not necessarily address zero.

> Head over to godbolt, compile it, and check the code.

I know what it compiles to on godbolt supported architectures. This is completely irrelevant.

Your code example, and its reasoning, contain so many errors that it's hard to know where to start.

You seem to insist that null pointer points to address zero. And you can try every architecture on godbolt, and it very likely does. But now you're just describing what happens when you do it, not the language and what can happen in the future.

Read this about how strange literal 0 and NULL is: https://c-faq.com/null/ptrtest.html

> So if you run that code on a system before the MMU is activated or on a system without a MMU, «main» will return 0 on all systems

"All systems"? What does that even mean? If you compile and run this on DOS you read from DS:0000 (or is it ES:0000?), which is not physical address zero, even though the MMU is not activated.

If you're using the Large or Huge memory model (https://en.wikipedia.org/wiki/X86_memory_models), then you may think that you'll read absolute value zero. Maybe in practice you do. But there's not necessarily a zero there. It'll be the first entry of the IVT.

But since you created null pointers (not "pointers to address zero"), and deferencing null pointers is UB, anything can happen. Including the compiler removing the code or just hard coding setting the result to zero.

But yeah, I'm not at all surprised that your misguided test gave you zero.

> Zero compilation warnings,

What's that supposed to signify? UB doesn't in any way what so ever imply warnings. -Wall doesn't even turn on all warnings anyway.

You can take ANY UB and "prove to me" what will happen by showing it on godbolt. But that just means you don't understand what UB even means.

> a read from 0 will give you 0 if the first memory page is filled with 0s.

This is also "not even wrong".

> You are most assuredly conflating a pointer to 0 dereferencing with the memory protection/virtual memory management system

Not even remotely.

> MMU is not magic.

You cannot think that I meant magic. Do you not understand what I meant? I meant you don't need an MMU to experience something other than plain naive address space mapped to physical RAM.

I've written a toy OS kernel with virtual memory, I know exactly what an MMU does.

> Respectfully, so far I am yet to see a single compelling argument or tangible piece of evidence to support the claims you have espoused.

So, everything you have said is wrong. A null pointer is not defined to point to address zero (see link above). So your code is nonsense. How am I supposed to provide some counter to that? Aside from where I have already said this, and it's plainly written in the C standard. (or, as it were, left undefined and thoroughly documented internet wide)

Dereferencing a null pointer is invalid. The spec says so:

> Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer[…]

c99 6.5.3.3 footnote 83.

You cannot dereference a null pointer according to the C language. And setting a pointer to literal 0 does not set any defined value of the pointer, other than setting it to the C "null pointer". Which could be any value. (again, see link above)

I "claim" that godbolt showing current compilers on some architectures do something specific is completely irrelevant to a discussion on UB. It could do the "common sense thing" (and almost always does), but it can do anything. You should read up on https://en.wikipedia.org/wiki/Undefined_behavior

When you say that you have not seen a single compelling argument, I think you're being hyperbolic. You said a system without an MMU will allow dereferencing a pointer to address zero (ignoring for now what that even is, in C). I replied that it's perfectly valid to have reads to address zero reset the machine.

What is your claim, that "no, the C standard does not allow resetting the machine when you read from address zero"? Even if a pointer to address zero and null pointer are the same (not defined by C), then per reference above it's invalid to dereference it.

> The only exception that does not initialiase memory with zeroes that I am aware of is AIX

What is this in regards to? It's seems extremely random. You are enumerating architectures whose bootup state have a certain initialized memory layout?

Why are you doing this? What point are you trying to prove?

I mean, it's also wrong. As we know from cold boot attacks, memory isn't just zeroed.

And when an x86 CPU starts up in real mode, address 0 has the interrupt vector table at address zero. So that's where interrupt 0 (divide error) handler far pointer goes. "Initialized to zero" doesn't make any sense. Entire books have been written about the x86 bootup process. Probably at some stages during an x86 boot address zero (virtual and/or physical) contain zero values, but it's not the long term contents.

Is an architecture that maps an I/O device for a temperature sensor at address zero an invalid architecture? Is it fundamentally incompatible with C? Of course not. Modern unix provides a user space where reading at address zero causes SEGV. But that's just one nuanced environment out of many.

> Again, embedded may have a nuance (subject to a specific hardware implementation) as it is a commonplace in embedded systems to not have a contiguous memory space and have holes in it

Vanilla unix user space is also noncontiguous with holes in it. Including usually (nowadays) a hole at address zero.

This is all completely unrelated to C language null pointers. Completely. You say I'm conflating things, but you're conflating null pointers with pointers to address zero. And with if address zero is initialized. And with MMU. None of which are relevant to any of the other things.

> Again, embedded may have a nuance

Everything has nuance. That's the entire point of the C standard. If you code to the C standard abstract machine, the compiler promises a certain observed behavior when run on the target. If you go beyond the standard (such as assuming nullptr points to address zero), then you are making assumptions about the nuances of the specific machine AND the compiler.

Linux has nuance. OpenBSD has nuance. Every embedded platform definitely has nuance. GCC has nuance (e.g. you can disable null check elision optimization. Is that true of MSVC? (I haven't used MSVC since last millenium).

But sure, if you say "my software only supports architectures where nullptr is zero, and built on a compiler that doesn't use this optimization", then that's your choice. It may be hard to enforce that over the lifetime of the program though, so maybe best to just write C code without UB. (which, as any expert will tell you, is nontrivial) Extra hard as future compilers or compiler versions introduce new ways of turning UB into "surprises".

Anyway, I'm done. Like I said, your theories about null pointers, UB, and architectures are intertwined in a web of misunderstanding that would take more than a HN thread to untangle.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: