Am Sat, Jun 21, 2025 at 04:07:54AM +0200 schrieb Alejandro Colomar: > I honestly still don't see the point in the camp returning NULL. The > only reason it hasn't died, I think, is because of fear of breaking > existing code, but I don't see anyone asking for that behavior. >
I invert the question: What is the point of requesting zero bytes? If you just want a pointer you cannot deref, but can validly plug into both realloc() and free(), I have this perfectly good null pointer right here. You can even statically initialize your variables with it. And you can easily tell it apart from pointers you can dereference. I see malloc(0) as an error. According to all standards I could get my hands on, the argument to malloc is supposed to be the size of an object, and in C, there are no objects without type, and no zero-sized types. Maybe that's different in C++, I don't know. I have read a bit of C code in my life, and have written some as well, and debugged even more of it. I cannot recall an instance of anyone ever requesting to allocate zero bytes except in error (e.g. uncaught overflow). Indeed, a strict reading of the spec would be that the argument must be the result of a sizeof expression, and the common idiom A *a = malloc(sizeof (A) + sizeof (B)); B *b = (B *)(a + 1); is undefined. And indeed, it potentially crashes on strict-alignment architectures if alignof(B) > alignof(A). Back to zero-sized allocations: The fact that they were traditionally supported on UNIX means nothing if they were always undefined. At that point it just becomes a quirk of the implementation, but nothing an application should depend on. The C89 mandate to free the pointer in case of zero-sized realloc (which I read as a command to *only* free the pointer and not do anything else) seems actively harmful: If an application can be tricked into doing that, and an implementation chooses to return the now freed pointer (since realloc must return /something/), then the application now holds a pointer it thinks is still valid, but is actually dangling. The way C89 (or rather FIPS160, which is the version I've read) has added the realloc-0-frees mandate, it looks like a badly thought through afterthought. But then, C89 also contains sprintf() and gets(), so badly thought through afterthoughts are certainly not a novelty to that particular writ. All standards after it have tinkered with the semantics of zero-sized allocation, to the point that C23 just made it explicitly undefined. As application developer, what inference do I draw from this, except to avoid zero-sized allocation like the plague? If anyone actually writes "realloc(p, 0)" intending it to be the same as "free(p)", I would tell them to then write what they mean and stop being so clever. As implementation developer, I would therefore treat these requests as errors, and do the appropriate thing: Return the error value and set errno to EINVAL (and have no further side effects). And such an implementation conforms to everything from C99 onwards. Ciao, Markus