Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can memset() be called with a null pointer if the size is 0?

Tags:

c

malloc

memset

For one reason or another, I want to hand-roll a zeroing version of malloc(). To minimize algorithmic complexity, I want to write:

void * my_calloc(size_t size)
{
    return memset(malloc(size), 0, size);
}

Is this well-defined when size == 0? It is fine to call malloc() with a zero size, but that allows it to return a null pointer. Will the subsequent invocation of memset be OK, or is this undefined behaviour and I need to add a conditional if (size)?

I would very much want to avoid redundant conditional checks!

Assume for the moment that malloc() doesn't fail. In reality there'll be a hand-rolled version of malloc() there, too, which will terminate on failure.

Something like this:

void * my_malloc(size_t size)
{
    void * const p = malloc(size);
    if (p || 0 == size) return p;
    terminate();
}

like image 208
Kerrek SB Avatar asked Dec 21 '11 22:12

Kerrek SB


People also ask

Does memset check for NULL?

AFAIK memset isn't required to check for NULL, so if the malloc fails you'll zero size bytes starting from address 0.

What does a null pointer do?

A null pointer has a reserved value that is called a null pointer constant for indicating that the pointer does not point to any valid object or function. You can use null pointers in the following cases: Initialize pointers. Represent conditions such as the end of a list of unknown length.

What happens when null pointer is freed?

It is safe to free a null pointer. The C Standard specifies that free(NULL) has no effect: The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs.

What is null in C?

The C and C++ languages have a null character (NUL), a null pointer (NULL), and a null statement (just a semicolon (;)). The C NUL is a single character that compares equal to 0. The C NULL is a special reserved pointer value that does not point to any valid data object.


2 Answers

Here is the glibc declaration:

extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));

The __nonnull shows that it expects the pointer to be non-null.

like image 114
Pubby Avatar answered Oct 07 '22 21:10

Pubby


Here's what the C99 standard says about this:

7.1.4 "Use of library functions"

If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.

7.21.1 "String function conventions" (remember that memset() is in string.h)

Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4.

7.21.6.1 "The memset function"

The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s.

So strictly speaking, since the standard specifies that s must point to an object, passing in a null pointer would be UB. Add the check (the cost compared to the malloc() will be vanishingly small). On the other hand, if you know the malloc() cannot fail (because you have a custom one that terminates), then obviously you don't need to perform the check before calling memset().

like image 29
Michael Burr Avatar answered Oct 07 '22 22:10

Michael Burr