Hacker News new | ask | show | jobs
by torstenvl 888 days ago
C99 and C11 have no special treatment for a size of zero. Since "memory for the new object [of size zero] cannot be allocated, the old object is not deallocated and its value is unchanged." (emphasis added). This is exactly what BSD does.

C17 says "If size is zero and memory for the new object is not allocated, it is implementation-defined whether the old object is deallocated" (emphasis added).

What standard, exactly, is BSD violating?

2 comments

Such behavior violates C89 (they later made it unspecified, likely to match the divergence):

> If size is zero and ptr is not a null pointer, the object it points to is freed.

It also violates every version of the SUS and POSIX up to Issue 6 (they made it unspecified in Issue 7):

> If size is 0 and ptr is not a null pointer, the object pointed to is freed.

Going down to at least the 3rd edition of SVID:

> If size is zero and ptr is not a null pointer, the object pointed to is freed.

What's obvious about all those Unix-related specifications is that they are not of BSD lineage.
That all refers to a failing allocation, obviously. If realloc cannot allocate the new object, the old one stays valid.

In the case of size zero, malloc(0) can return null (always). That is ambiguous; it looks like a failure. If realloc literally were to call malloc(0) and then treats the null as a failure, it will return the old object. However, on an implementation where malloc(0) always returns null by design, that would be obviously be poor behavior for its own realloc.

If malloc(0) returns null by design that is not a case where allocating an object failed.

We basically now need this in every program that might resize to zero:

  void *sane_realloc(void *ptr, size_t size)
  {
     if (size == 0) {
       free(ptr);
       return malloc(0);
     }
     return realloc(ptr, size);
  }
The only problem is that if malloc(0) returns null on an implementation where it normally returns an allocated pointer (and thus the call has failed) we don't detect the failure and don't preserve the original object. The application which relies on sane_realloc has to understand that when size is zero, the deallocation always works, whether or not the subsequent malloc does, and so it may get a null pointer on any platform.