...
The erroneous behavior results form from getStock()
returning NULL
while main()
forgets to add in a check for such a value. In this noncompliant code example, the check for item != null
is missing from the if
condition in function main()
.
Wiki Markup |
---|
In the example below, there is an inventory system keeping track of the total number of different items (denoted {{length |
length
in the struct and a value would be assigned for stock. If there are no items being stocked, however, then the below code}}). Each item is given an index in the array, and the value for that index is the stock of that item. Adding a new item would increase {{length}} in the struct. Stocking more of an item would increase the value for that item's index. For example, if 5 books and 2 erasers were in stock, the inventory would be {{stockOfItem\[0\] = 5}} and {{stockOfItem\[1\] = 2}}, assuming books were index 0 and erasers were index 1. |
The problem arises in this setup when no items are being stocked. getStock
would recognize that length = 0
and thus would return NULL
. This would result in an abnormal program termination after returning to the main
function.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> enum { INV_SIZE=20 }; typedef struct { size_t stockOfItem[INV_SIZE]; size_t length; } Inventory; intsize_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; } intsize_t *getStock(Inventory iv) { if (iv.length == 0) { return NULL; } else { return iv.stockOfItem; } } |
...
This compliant solution eliminates the NULL
return and simply returns the item
array as is , even if it is zero-length. The main function can effectively handle this situation without exhibiting erroneous behavior.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> enum { INV_SIZE=20 }; typedef struct { size_t stockOfItem[INV_SIZE]; size_t length; } Inventory; intsize_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); printf("Stock of first item in inventory: %d\n", item[0]); return 0; } intsize_t *getStock(Inventory iv) { return iv.stockOfItem; } |
Noncompliant Code Example (Sentinel Value)
The code below implements an inventory system similar to the one described above. However, instead of storing the length of the array in a struct, a sentinel value of -1 is used. The value for the index following the last item is set as -1. It is assumed that out of stock items (assigned value 0) are removed from the array, and the contents of later items shifted to lower indexes.
The example below attempts to return an array of the items in stock, sorted by the amount of each item in stock. The arraySort
function below also incorrectly returns NULL
instead of a pointer to an empty array . arraySort
returns NULL
when the size of the array is zerowhen no items are in stock. This will be improperly handled by the main function, which is attempting to print out the resulting returned array. This will result in an abnormal program termination.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> enum { 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] != -1; 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] != -1; 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*/ } |
...
The example below correctly returns an empty array in the sortedArray
function. If the size of the array is zero, then sortedArray
allocates an array of size 1 and fills it with the sentinel value (assumed to be -1). It can then successfully return that array to the caller function.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> enum { 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] != -1; 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] != -1; i++); if (i == 0) { sortedArray = (size_t*) malloc(sizeof(size_t)); if(sortedArray == NULL) { /* Handle memory error */ } sortedArray[0] = -1; return sortedArray; } sortedArray = (size_t*) malloc(sizeof(size_t)*i); if (sortedArray == NULL) { /* Handle memory error */ } /* Add sorted data to array*/ } |
...
Returning NULL
rather than a zero-length array may lead to vulnerabilities when the client code does not handle null
NULL
properly. This can result in abnormal program termination when the calling function performs operations on NULL
.
...
References
Wiki Markup |
---|
\[[Bloch 08|java:AA. Java References#Bloch 08]\] Item 43: return empty arrays or collections, not nulls |
...