Versions Compared

Key

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

Many functions have the option of returning a pointer to an object or returning NULL if a valid pointer cannot be produced. Some functions return arrays, which appear like a pointer to an object. However, if a function has the option of returning an array or indicating that a valid array is not possible, it should not return NULL. Instead, the function should return an empty array. Often, code that calls a function that returns an array intends merely to iterate over the array elements. In this case, the calling code need not change—iterating over the elements works correctly even if the returned array is empty, so the calling code need not check the return value for NULL.

...

The problem arises in this setup when no items are being stocked. getStock would recognize that length = 0 and would return NULL. In this noncompliant code example, erroneous behavior results from getStock returning NULL while main neglects to check for such a value. It results in an abnormal program termination after returning to the main function.

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
enum { INV_SIZE=20 };

typedef struct {
  size_t stockOfItem[INV_SIZE];
  size_t length;
} Inventory;

size_t *getStock(Inventory iv);

int main(void) {
  Inventory iv;
  size_t *item;

  iv.length = 0;

  /*
   * Other code that might modify the inventory but still
   * leave no items in it upon completion.
   */

  item = getStock(iv);

  printf("Stock of first item in inventory: %d\n", item[0]);
  
  return 0;
}

size_t *getStock(Inventory iv) {
  if (iv.length == 0) {
    return NULL;
  }
  else {
    return iv.stockOfItem;
  }
}

...

Code Block
bgColor#ccccff
langc
#include <stdio.h>

enum { INV_SIZE=20 };

typedef struct {
  size_t stockOfItem[INV_SIZE];
  size_t length;
} Inventory;

size_t *getStock(Inventory iv);

int main(void) {
  Inventory iv;
  size_t i;
  size_t *item;

  iv.length = 0;
  
  /*
   * Other code that might modify the inventory but still
   * leave no items in it upon completion.
   */
  
  item = getStock(iv);

  if (iv.length != 0) {
    printf("Stock of first item in inventory: %d\n", item[0]);
  }
  
  return 0;
}

size_t *getStock(Inventory iv) {
  return iv.stockOfItem;
}

...

The following code attempts to return an array of the items in stock, sorted by the amount of each item in stock. The arraySort function incorrectly returns NULL instead of a pointer to an empty array when no items are in stock. The null return is improperly handled by the main function, which is attempting to print out the returned array, and an abnormal program termination results.

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>

enum { FINAL_ITEM=SIZE_MAX, INV_SIZE=20 };

size_t *arraySort(size_t *array);

int main(void) {
  size_t i;
  size_t stockOfItem[INV_SIZE];
  size_t *sortedArray;

  /* Other code that might use stockarray but leaves it empty */

  sortedArray = arraySort(stockOfItem);
  
  for (i = 0; sortedArray[i] != FINAL_ITEM; i++) {
	printf("Item stock: %d", sortedArray[i]);
  }
  
  return 0;
}

/* Create new sorted array */
size_t *arraySort(size_t *array) {
  size_t i;
  size_t *sortedArray;

  for(i = 0; array[i] != FINAL_ITEM; i++);
  
  if (i == 0) {
    return NULL;
  }

  sortedArray = (size_t*) malloc(sizeof(size_t)*i);
  if (sortedArray == NULL) {
    /* Handle memory error */
  }

  /* Add sorted data to array */

  return sortedArray;
}

Compliant Solution (Sentinel Value)

...

Code Block
bgColor#ccccff
langc
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>

enum { FINAL_ITEM=SIZE_MAX, INV_SIZE=20 };

size_t *arraySort(size_t *array);

int main(void) {
  size_t i;
  size_t stockOfItem[INV_SIZE];
  size_t *sortedArray;


  /* Other code that might use stockarray but leaves it empty */

  sortedArray = arraySort(stockOfItem);
  
  for (i = 0; sortedArray[i] != FINAL_ITEM; i++) {
    printf("Item stock: %d", sortedArray[i]);
  }
  
  return 0;
}

/* Create new sorted array */
size_t *arraySort(size_t *array) {
  size_t i;
  size_t *sortedArray;

  for(i = 0; array[i] != FINAL_ITEM; i++);

  if (i == 0) {
    size_t *emptyArray = (size_t*) malloc(sizeof(size_t));
    if(emptyArray == NULL) {
      /* Handle memory error */
    }
    emptyArray[0] = FINAL_ITEM;
    return emptyArray;
  }
  
  sortedArray = (size_t*) malloc(sizeof(size_t)*i);
  if (sortedArray == NULL) {
    /* Handle memory error */
  }

  /* Add sorted data to array */

  return sortedArray;
 }

...

Returning NULL rather than a zero-length array can lead to vulnerabilities when the client code does not handle NULL properly. Abnormal program termination can result when the calling function performs operations on NULL.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MSC19-C

lowLow

unlikelyUnlikely

highHigh

P1

L3

Related Vulnerabilities

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

...