Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The results of allocating zero bytes of memory are implementation dependent. According to C99 Section 7.20.3 ISO/IEC 9899-1999When the requested size is 0, the behavior of the memory allocation functions malloc(), calloc(), and realloc() is implementation-defined. Subclause 7.22.3 of the C Standard [ISO/IEC 9899:2011] states:

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 some nonzero value, except that the returned pointer shall not be used to access an object.

In addition, the amount of storage allocated by a successful call to the allocation function when 0 bytes was requested is unspecified. See unspecified behavior 41 in subclause J.1 of the C Standard.

This includes all three standard memory allocation functions: malloc(), calloc(), and realloc(). In cases where the memory allocation functions return a non-NULL null pointer, using this pointer reading from or writing to the allocated memory area results in undefined behavior. Typically these , the pointer refer refers to a zero-length block of memory consisting entirely of control structures. Overwriting these control structures will damage damages the data structures used by the memory manager.

Noncompliant Code Example (malloc())

...

The result of calling malloc(0) to allocate 0 bytes is implementation-defined. In this example, a dynamic array of integers is allocated to store s size elements. However, if s size is zero0, the call to malloc(ssize) may return a reference to a block of memory of size 0 rather than NULLinstead of a null pointer. When (nonempty) data is copied to this location, a heap-buffer overflow occurs.

Code Block
bgColor#FFcccc
langc
size_t size;

/* ... Initialize size, possibly by user-controlled input */

int *list = malloc(sizeof(int) * s)malloc(size);
if (list == NULL) {
  /* Handle Allocationallocation Errorerror */
}
else {
/* Continue Processingprocessing list */
/* ... */}

Compliant

...

Solution (malloc())

To ensure that 0 is never passed as a size argument to malloc(), size is checked to confirm it has a positive value: Wiki MarkupTo ensure that zero is never passed as a size argument to {{malloc()}}, a check must be made on {{s}} to ensure it is not zero. Note that this solution checks for numeric overflow \[[INT32-C. Ensure that integer operations do not result in an overflow]\].

Code Block
bgColor#ccccff
langc
size_t size;

if/* (s == 0) {
  /* Handle Error Initialize size, possibly by user-controlled input */
}
if (sizeof(int) > SIZE_MAX/ssize == 0) {
   /* handleHandle overflowerror */
}
int *list = malloc(sizeof(int) * s)malloc(size);
if (list == NULL) {
  /* Handle Allocationallocation Errorerror */
}
/* Continue Processingprocessing list */
/* ... */

Noncompliant Code Example (realloc())

Non-Compliant Code Example

The realloc() function deallocates the old object and returns a pointer to a new object of a specified size. If memory for the new object cannot be allocated, the realloc() function does not deallocate the old object, and its value is unchanged. If the realloc() function returns NULL, failing to free the original memory will result in a memory leak. As a result, the following idiom is generally often recommended for reallocating memory:

Code Block
bgColor#FFcccc
langc
size_t nsize = /* Some value, possibly user supplied */;
char *p2;
char *p = (char *)malloc(100);
if (p == NULL) {
  /* Handle error */
}

/* ... */

if ((p2 = (char *)realloc(p, nsize)) == NULL) {
  if (p) free(p);
  p = NULL;
  return NULL;
}
p = p2;

However, this commonly recommended idiom has problems with zero-length allocations. If the value of nsize in this example is 0, the standard allows the option of either returning a null pointer or returning a pointer to an invalid (e.g.for example, zero-length) object. In cases where the realloc() function frees the memory but returns a null pointer, execution of the code in this example results in a double-free vulnerability. If the realloc() function returns a non-null value, but the size was 0, the returned memory will be of size 0, and a heap overflow will occur if nonempty data is copied there.

Implementation Details

The realloc() function for gcc If this noncompliant code is compiled with GCC 3.4.6 and linked with libc 2.3.4, invoking realloc(p, 0) returns a non-NULL null pointer to a zero-sized object (the same as malloc(0)). However, the realloc() function for both if the same code is compiled with either Microsoft Visual Studio Version 7.1 and gcc version or GCC 4.1.0 return , realloc(p, 0) returns a null pointer, resulting in a double free on the call to free() in this example-free vulnerability.

Compliant

...

Solution (realloc())

This compliant solution does Do not pass a size argument of zero to the realloc() function.:

Code Block
bgColor#ccccff
langc
size_t nsize;
/* Initialize nsize */
char *p2;
char *p = (char *)malloc(100);
if (p == NULL) {
  /* Handle error */
}

/* ... */

p2 = NULL;
if ( (nsize =!= 0) {
 || (p2 = (char *)realloc(p, nsize));
}
if (p2 == NULL) {
  if (p) free(p);
  p = NULL;
  return NULL;
}
p = p2;

Risk Assessment

Assuming that allocating zero bytes results in an error Allocating 0 bytes can lead to buffer overflows when zero bytes are allocated. Buffer overflows can be exploited by an attacker to run arbitrary code with the permissions of the vulnerable process. abnormal program termination.

Recommendation

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MEM04-

A

3 (high)

2 (probable)

2 (medium)

P12

L1

C

Low

Likely

Medium

P6

L2

Automated Detection

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V

Supported, but no explicit checker
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
(customization)Users can add a custom check for allocator calls with size argument 0 (this includes literal 0, underconstrained tainted values, and computed values). 
Compass/ROSE



Can detect some violations of this rule. In particular, it warns when the argument to malloc() is a variable that has not been compared against 0 or that is known at compile time to be 0

Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_C-MEM04-aThe validity of values passed to library functions shall be checked
Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rec. MEM04-C


Checks for:

  • Variable length array with nonpositive size
  • Tainted sign change conversion
  • Tainted size of variable length array

Rec. fully covered.

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

...

Related Guidelines

 Bibliography

...

...

9899:2011]Section 7.22.3,

...

"Memory

...

Management

...

Functions"

...


...

Image Added Image Added Image Added 05|AA. C References#Seacord 05]\] Chapter 4, "Dynamic Memory Management"