views:

376

answers:

4

I am a beginner in C. While reading git's source code, I found this wrapper function around malloc.

void *xmalloc(size_t size)
{
    void *ret = malloc(size);
    if (!ret && !size)
        ret = malloc(1);
    if (!ret) {
        release_pack_memory(size, -1);
        ret = malloc(size);
        if (!ret && !size)
            ret = malloc(1);
        if (!ret)
            die("Out of memory, malloc failed");
    }
#ifdef XMALLOC_POISON
    memset(ret, 0xA5, size);
#endif
    return ret;
}

Questions

  1. I couldn't understand why are they using malloc(1)?
  2. What does release_pack_memory does and I can't find this functions implementation in the whole source code.
  3. What does the #ifdef XMALLOC_POISON memset(ret, 0xA5, size); does?

I am planning to reuse this function on my project. Is this a good wrapper around malloc?

Any help would be great.

+2  A: 

For question 1:

The standard does not define the behavior of malloc(0). That may return a valid pointer or it may return NULL. Different implementations handle that differently so the code falls back to malloc(1) to get consistent behavior.

For question 3:

It sets the contents of the buffer to something 'strange'. This way, your code is hopefully not relying on the contents being something specific (which malloc does not guarantee).

R Samuel Klatchko
Do you recommend using this wrapper?
Appu
@Appu - changing 0 to 1 and doing the memset is fine. The die on OOM policy depends on what you are writing. The policy is fine for a command line utility that does one thing and exits. The policy may or may not be fine for a long lived server (do you want to exit the process or do you want to clean up the current request and try again). The policy is not acceptable for a generic library as the policy on OOM should be decided by the main application.
R Samuel Klatchko
Good point. The code which I will be writing is for a library. So I think I should avoid `die`.
Appu
"Should it return a valid pointer that has no memory associated with it or should it return NULL?" - Ooh, I can answer that, "yes" ;-) Not sure whether your answer makes clear that the implementation must do one or the other. And that if it's a valid pointer, then it's a different one each time.
Steve Jessop
+3  A: 
  1. malloc(0) does not work on all a platforms, in which case a one-byte allocation is made instead. Allowing the allocation of 0-length memory blocks simplifies the higher-level logic of the program.

  2. Don't know.

  3. By filling the allocated memory with a non-zero value, it is easier to find bugs in the program where the memory is used without proper initialization: the program will crash almost immediately in such cases. As filling the memory takes time, it is wrapped in a preprocessor define, so it is compiled in only when desired.

Lars
The behaviour of 'malloc(0)' is implementation defined. It either returns a NULL pointer or a non-null pointer to zero bytes of data (which, of course, you can never dereference). C99 §7.20.3 Memory management functions: "If the size of the space requested is zero, the behavior is implementation defined:either a null pointer is returned, or the behavior is as if the size were somenonzero value, except that the returned pointer shall not be used to access an object."
Jonathan Leffler
+1  A: 

For question 2: release_pack_memory is found in sha1_file.c:570.

AKX
+1  A: 

I am not familiar with this wrapper but here is what its doing

1 - if size=0 was specified then it allocates 1 byte instead if the underlying malloc did not do so

this is presumably done so that a caller can still do free on it (like realloc)

2 I assume its to try to force the underlying memory subsystem to look harder for memory

3 the XMALLOC_POISON forces to buffer to a known state this is common practice in order to prevent and detect odd bugs caused by uninitialized data

Secondly - why do you want to wrap malloc. Start with the idea of what you want to do and then implement it or copy an implementation. Reasons for wrapping malloc

  1. leak detection
  2. usage analysis
  3. memory pooling
  4. debugging (like the XMALLOC_POISON)
  5. enforced checking

Almost all of these can be done with valgrind - which does much more.

'writing solid code' book has good set of memory wrappers for 1,4 and 5

pm100
Thanks for the answer. Honestly, I am bit lost in the C world. So to avoid me doing mistakes, I am reading other programs code and finding out how they write code.
Appu
"this is presumably done so that a caller can still do free on it" - you can still call free or realloc on a null pointer. I don't know git's source, but more likely it's done in order to ensure that a 0 return can definitively be treated by the caller as an error, even if the input was 0. Or possibly to ensure that the pointers to different 0-sized allocations compare different ("this isn't your zero-sized buffer, so that must not be your suitcase!").
Steve Jessop