Main Content

CERT C: Rule MEM35-C

Allocate sufficient memory for an object

Description

Rule Definition

Allocate sufficient memory for an object.1

Polyspace Implementation

The rule checker checks for these issues:

  • Pointer access out of bounds.

  • Memory allocation with tainted size.

  • Insufficient memory allocation

Extend Checker

A default Bug Finder analysis might not flag a Memory allocation with tainted size issue for certain inputs that originate outside of the current analysis boundary. See Sources of Tainting in a Polyspace Analysis. To consider any data that does not originate in the current scope of Polyspace analysis as tainted, use the command line option -consider-analysis-perimeter-as-trust-boundary.

Examples

expand all

Issue

Pointer access out of bounds occurs when a pointer is dereferenced outside its bounds.

When a pointer is assigned an address, a block of memory is associated with the pointer. You cannot access memory beyond that block using the pointer.

Risk

Dereferencing a pointer outside its bounds is undefined behavior. You can read an unpredictable value or try to access a location that is not allowed and encounter a segmentation fault.

Fix

The fix depends on the root cause of the defect. For instance, you dereferenced a pointer inside a loop and one of these situations happened:

  • The upper bound of the loop is too large.

  • You used pointer arithmetic to advance the pointer with an incorrect value for the pointer increment.

To fix the issue, you have to modify the loop bound or the pointer increment value.

Often the result details show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show the event history, you can trace back using right-click options in the source code and see previous related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface.

See examples of fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Example - Pointer access out of bounds error
int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
   {
    ptr++;
    *ptr=i; //Noncompliant
    /* Defect: ptr out of bounds for i=9 */
   }

 return(arr);
}

ptr is assigned the address arr that points to a memory block of size 10*sizeof(int). In the for-loop, ptr is incremented 10 times. In the last iteration of the loop, ptr points outside the memory block assigned to it. Therefore, it cannot be dereferenced.

Correction — Check Pointer Stays Within Bounds

One possible correction is to reverse the order of increment and dereference of ptr.

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
     {
      /* Fix: Dereference pointer before increment */
      *ptr=i;
      ptr++;
     }

 return(arr);
}

After the last increment, even though ptr points outside the memory block assigned to it, it is not dereferenced more.

Issue

Memory allocation with tainted size checks memory allocation functions, such as calloc or malloc, for size arguments from unsecured sources.

Risk

Uncontrolled memory allocation can cause your program to request too much system memory. This consequence can lead to a crash due to an out-of-memory condition, or assigning too many resources.

Fix

Before allocating memory, check the value of your arguments to check that they do not exceed the bounds.

Example — Allocate Memory Using Input From User
#include<stdio.h>
#include <stdlib.h>

int* bug_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = (int*)malloc(size); //Noncompliant
    return p;
}

In this example, malloc allocates size bytes of memory for the pointer p. The variable size comes from the user of the program. Its value is not checked, and it could be larger than the amount of available memory. If size is larger than the number of available bytes, your program could crash.

Correction — Check Size of Memory to be Allocated

One possible correction is to check the size of the memory that you want to allocate before performing the malloc operation. This example checks to see if size is positive and less than the maximum size.

#include<stdio.h>
#include <stdlib.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

int* corrected_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = NULL;
    if (size>0 && size<SIZE128) {          /* Fix: Check entry range before use */
        p = (int*)malloc((unsigned int)size);
    }
    return p;
}
Issue

Insufficient memory allocation occurs when the allocated memory is not sufficient to hold the target object. Consider this code:

typedef struct S {
    int a;
    int b;
    int c;
}S;

void foo(){
	S* a;
	a = (S*)malloc(sizeof(S*)*2);//Noncompliant	
}
void bar(){
	S* a;
	a = (S*)malloc(sizeof(S*)*3); //Compliant	
}
Objects of type S must accommodate three integers, which typically requires 12 bytes of memory. In foo() the allocated memory size for the S type object is eight bytes. Because the allocated memory is insufficient to hold the target object, Polyspace® reports a violation of this rule. In bar(), the allocated memory is 12 bytes, which is sufficient. Polyspace does not report a violation.

Risk

Insufficient memory allocation results in buffer overflow and unexpected termination of the program.

Fix

When allocating memory blocks, allocate sufficient memory.

Example — Allocate Memory for Objects by Calling malloc()

In this example, the function foo() allocates memory for pointers a and b:

  • When allocating memory for a, the argument of sizeof() is S*, which is a pointer. In a 64 bit system, all pointer types are 8 bytes in size. The malloc() statement allocates 24 bytes, which is sufficient to accommodate an object of S type. Because the allocated memory can hold the a object, Polyspace does not report a violation. This statement causes a Wrong type used in sizeof defect.

    From the context of the malloc() statement, the object a is intended to be a three element array of S type objects. Clearly, the malloc() statement does not allocate sufficient memory for the entire array. In the for loop, when you access the elements of the array, the insufficient memory causes a violation of this rule. This way, the Wrong type used in sizeof defect in the malloc() statement causes a violation of this rule when you use a as an array. If you use a as an object instead of an array, this rule is not violated.

  • When allocating memory for b, the malloc() statement allocates enough memory to accommodate two integers. Because objects of type S require enough memory to accommodate three integers, the allocated memory is insufficient. Polyspace reports a violation of this rule.

#include <stdlib.h>


typedef struct S
{
  int a;
  int b;
  int c;
} S;

void setS (S * a, int x, int y, int z)
{
  a->a = x;			//Noncompliant: pointer access out of bounds
  a->b = y;
  a->c = z;
}

void foo ()
{
  S *a, *b;
  a = (S *) malloc (3 * sizeof (S *));	//Compliant but causes PTR_SIZEOF_MISMATCH defect/
  setS(a,22,32,45); //Compliant
  for (int i = 1; i < 3; ++i)
    {
      setS (a + i, i, i * i, i * i * i);

    }
  b = (S *) malloc (2 * sizeof (int));	//Noncompliant 

}
Correction — Allocate Sufficient Memory

To fix this issue, allocate sufficient memory. The best practice is to use the sizeof() function with correct argument type and a correct multiplier to calculate how much memory is required.

#include <stdlib.h>


typedef struct S
{
  int a;
  int b;
  int c;
} S;

void setS (S * a, int x, int y, int z)
{
  a->a = x;			//Compliant: pointer access out of bounds
  a->b = y;
  a->c = z;
}

void foo ()
{
  S *a, *b;
  a = (S *) malloc (3 * sizeof (S));	//No violations of PTR_SIZEOF_MISMATCH*/
  setS(a,22,32,45); //Compliant
  for (int i = 1; i < 3; ++i)
    {
      setS (a + i, i, i * i, i * i * i);

    }
  b = (S *) malloc (1 * sizeof (S));	//Compliant 
  //...
  free(a);
  free (b);
}

Check Information

Group: Rule 08. Memory Management (MEM)

Version History

Introduced in R2019a

expand all


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.