Seeking code correctness and best practices.

I would like to re-allocate various amounts of memory (0 or more) such that on systems that may return NULL for an allocation of 0 does not falsely imply a memory allocation error.

Given:

  • void * (with a valid value or NULL already)
  • size_t (new desired size)

Receive:

  • void * (new pointer)
  • int (failure status)

#include <assert.h>
#include <stdlib.h>

int ReallocAndTest(char **Buf, size_t NewSize) {
  assert(Buf);
  char *NewBuf = realloc(*Buf, NewSize);
  if ((NewBuf == NULL) && (NewSize > 0)) {
    return 1;  // return failure
  }
  *Buf = NewBuf;
  return 0;
}

I came across the below references, which imply a realloc() return of NULL is not always a failure. The lone special case occurs with size is 0. The return value may or may not be NULL.

C11dr 7.22.3.5 The realloc function 4 The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

C11dr §J.1 Unspecified behavior. — The amount of storage allocated by a successful call to the calloc, malloc, or realloc function when 0 bytes was requested (7.22.3).

C11dr §J.3.12 Implementation-defined behavior. Whether the calloc, malloc, and realloc functions return a null pointer or a pointer to an allocated object when the size requested is zero (7.22.3).


[Answer]

  1. Use void* rather than char *.

  2. With a 0 size, avoid returning the implementation defined
    ..a) NULL or
    ..b) ptr that cannot be referenced.
    and return a pointer to insure only 1 of the 2 is ever returned.

On point #2, I only slightly favor returning NULL.

  • I already see I should be using void * rather than char *. – chux Dec 4 '13 at 21:45
  • For semantic consistency, you might want to change 0 to FALSE, 1 to TRUE and int to bool(C++) or bool_t/BOOL/BOOLEAN (or whatever standard bool type you're using in your C program). That will make it more clear to callers what they should expect the function to do. – Matt Dec 8 '13 at 10:00
up vote 6 down vote accepted
  1. Standard naming convention in C is usually lower_case_with_underscore.

  2. You should be using void * rather than char *

  3. I would consider making the return value deterministic when the new size is 0 by always returning NULL rather than the implementation defined behaviour (which could technically be a pointer which is not NULL but still not allowed to be dereferenced). free guarantees by spec that free(NULL) is legal.

  • I am unfamiliar with the standard in 1. Where may I find it? – chux Dec 5 '13 at 0:09
  • The wiki says "standard library identifiers are mostly lowercase" and this is not a standard library identifier. Sorry if the "wrapper" description misled. The SO post reflect various conventions but not a standard. The C standard does distinguish between upper and lower case letter in all identifiers, so this implies that upper case usage is not verboten. The SO post did stress consistency. I concur with your naming convention of trying to be standard. – chux Dec 6 '13 at 18:54
  • 2
    Yes, naming conventions are always subjective. However PascalCase for local variables and function parameters is rather unusual. – ChrisWue Dec 7 '13 at 0:12
  • This is a good "patch critique" for the given wrapper. The other answer explains a better wrapper. – Sam Watkins Feb 3 '15 at 12:20

With the variety of behaviors exhibited by different implementations, I think the only safe thing is to test for zero size before the realloc call and set a minimum allocation (eg 1 byte).

Note that realloc will probably set errno to ENOMEM when it fails, but I don't think this is guaranteed.

  • 1
    ENOMEM appears to be in Linux and not the C standard. It is surprising that a memory allocation error does not generate a error code per the C standard. Maybe a history thing. – chux Dec 5 '13 at 0:15
  • 3
    +1 Checking for 0 before calling realloc is indeed the correct approach. Avoid writing code that relies on unspecified or impl.defined behavior. One of the point of writing a wrapper is to get rid of such things. – Lundin Dec 10 '13 at 11:53
  • 1
    I (also) suggest if someone calls your_malloc() or your_realloc() with size 0, you should call malloc() or realloc() with size 1. That way you always have a distinct pointer. Some code may benefit from the assumption that distict allocated objects have distinct addresses; and of course it's not good to be confused between success and failure! I did this in my malloc and realloc wrappers: sam.nipl.net/libb/alloc.b Additionally, this allows your_malloc and your_realloc to be signature compatible with the originals. – Sam Watkins Feb 3 '15 at 12:13

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.