CERT C: Rule ERR33-C
Detect and handle standard library errors
Description
Rule Definition
Detect and handle standard library errors.1
Polyspace Implementation
The rule checker checks for these issues:
Errno not checked.
Returned value of a sensitive standard function not checked.
Unprotected dynamic memory allocation.
Pointer overwritten during reallocation.
Examples
Errno not checked
Errno not checked occurs when
you call a function that sets errno
to indicate
error conditions, but do not check errno
after
the call. For these functions, checking errno
is
the only reliable way to determine
if an error occurred.
Functions that set errno
on errors include:
fgetwc
,strtol
, andwcstol
.For a comprehensive list of functions, see documentation about errno.
POSIX®
errno
-setting functions such asencrypt
andsetkey
.
To see if the function call completed without errors, check errno
for
error values.
The return values of these errno
-setting
functions do not indicate errors. The return value can be one of the
following:
void
Even if an error occurs, the return value can be the same as the value from a successful call. Such return values are called in-band error indicators.
You can determine if an error occurred only by checking errno
.
For instance, strtol
converts a string to
a long integer and returns the integer. If the result of conversion
overflows, the function returns LONG_MAX
and sets errno
to ERANGE
.
However, the function can also return LONG_MAX
from
a successful conversion. Only by
checking errno
can you distinguish between an error
and a successful
conversion.
Before calling the function, set errno
to
zero.
After the function call, to see if an error occurred, compare errno
to
zero. Alternatively, compare errno
to known error
indicator values. For instance, strtol
sets errno
to ERANGE
to
indicate errors.
The error message in the Polyspace® result shows the error indicator value that you can compare to.
errno
Not Checked After Call to strtol
#include<stdio.h> #include<stdlib.h> #include<errno.h> int main(int argc, char *argv[]) { char *str, *endptr; int base; str = argv[1]; base = 10; long val = strtol(str, &endptr, base); //Noncompliant printf("Return value of strtol() = %ld\n", val); }
You are using the return value of strtol
without
checking errno
.
errno
After CallBefore calling strtol
, set
errno
to zero. After a call to strtol
,
check the return value for LONG_MIN
or
LONG_MAX
and errno
for
ERANGE
.
#include<stdlib.h> #include<stdio.h> #include<errno.h> #include<limits.h> int main(int argc, char *argv[]) { char *str, *endptr; int base; str = argv[1]; base = 10; errno = 0; long val = strtol(str, &endptr, base); if((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) { printf("strtol error"); exit(EXIT_FAILURE); } printf("Return value of strtol() = %ld\n", val); }
Returned value of a sensitive standard function not checked
Returned value of a sensitive standard function not checked occurs when you call sensitive standard functions, but you:
Ignore the return value.
Use an output or a return value without testing the validity of the return value.
For this defect, two type of functions are considered: sensitive and critical sensitive.
A sensitive function is a standard function that can encounter:
Exhausted system resources (for example, when allocating resources)
Changed privileges or permissions
Tainted sources when reading, writing, or converting data from external sources
Unsupported features despite an existing API
A critical sensitive function is a sensitive function that performs one of these critical or vulnerable tasks:
Set privileges (for example,
setuid
)Create a jail (for example,
chroot
)Create a process (for example,
fork
)Create a thread (for example,
thrd_create
)Lock or unlock memory segments (for example,
mlock
)
If you do not check the return value of functions that perform sensitive or critical sensitive tasks, your program can behave unexpectedly. Errors from these functions can propagate throughout the program causing incorrect output, security vulnerabilities, and possibly system failures.
Before continuing with the program, test the return value of critical sensitive functions.
For sensitive functions, you can explicitly
ignore a return value by casting the function to void
. Polyspace does
not raise this defect for sensitive functions cast to void. This resolution
is not accepted for critical sensitive functions because
they perform more vulnerable tasks.
#include<stdio.h> #include <wchar.h> #include <locale.h> void initialize(size_t n, size_t* size, wchar_t *wcs, const char *utf8) { scanf("%d",&n); //Noncompliant setlocale (LC_CTYPE, "en_US.UTF-8"); //Noncompliant *size = mbstowcs (wcs, utf8, n); }
This example shows a call to the sensitive function
scanf()
. The return value of scanf()
is
ignored, causing a defect. Similarly, the pointer returned by
setlocale
is not checked. When
setlocal
returns a NULL
pointer, the
call to mbstowcs
might fail or produce unexpected results.
Polyspace flags these calls to sensitive functions when their returns are not
checked.
(void)
One possible correction is to cast the functions to void. This fix informs Polyspace and any reviewers that you are explicitly ignoring the return value of these sensitive functions.
#include<stdio.h> #include <wchar.h> #include <locale.h> void initialize(size_t n, size_t* size, wchar_t *wcs, const char *utf8) { (void)scanf("%d",&n); //Compliant (void)setlocale (LC_CTYPE, "en_US.UTF-8"); //Compliant *size = mbstowcs (wcs, utf8, n); }
One possible correction is to test the return value of
scanf
and setlocale
to check for
errors.
#include<stdio.h> #include <wchar.h> #include <locale.h> void initialize(size_t n, size_t* size, wchar_t *wcs, const char *utf8) { int flag = scanf("%d",&n); if(flag>0){ //Compliant // action } char* status = setlocale (LC_CTYPE, "en_US.UTF-8"); if(status!=NULL){//Compliant *size = mbstowcs (wcs, utf8, n); } }
#include <threads.h> int thrd_func(void); void initialize() { thrd_t thr; int n = 1; (void) thrd_create(&thr,thrd_func,&n); //Noncompliant }
In this example, a critical function thrd_create
is called
and its return value is ignored by casting to void, but because
thrd_create
is a critical function, Polyspace does not
ignore this defect.
The correction for this defect is to check the return value of these critical functions to verify the function performed as expected.
#include <threads.h> int thrd_func(void); void initialize() { thrd_t thr; int n = 1; if( thrd_success!= thrd_create(&thr,thrd_func,&n) ){ // handle error } }
Unprotected dynamic memory allocation
Unprotected dynamic memory allocation occurs when you do not check after dynamic memory allocation whether the memory allocation succeeded.
When memory is dynamically allocated using malloc
,
calloc
, or realloc
, it returns a value
NULL
if the requested memory is not available. If the code
following the allocation accesses the memory block without checking for this
NULL
value, this access is not protected from
failures.
Check the return value of
malloc
, calloc
, or
realloc
for NULL before accessing the allocated memory
location.
#DEFINE SIZE 8; int *ptr = malloc(SIZE * sizeof(int)); if(ptr) /* Check for NULL */ { /* Memory access through ptr */ }
#include <stdlib.h> void Assign_Value(void) { int* p = (int*)calloc(5, sizeof(int)); *p = 2; //Noncompliant /* Defect: p is not checked for NULL value */ free(p); } /*Defect: p is not checked for NULL before deallocating*/
If the memory allocation fails, the function such as
calloc
returns NULL
to
p
. Before accessing the memory through
p
or freeing p
, the code does not
check whether p
is NULL
. These
operations might result in memory leaks.
One possible correction is to check whether p
has value
NULL
before dereference.
#include <stdlib.h> void Assign_Value(void) { int* p = (int*)calloc(5, sizeof(int)); /* Fix: Check if p is NULL */ if(p!=NULL) *p = 2; free(p); }
Pointer overwritten during reallocation
Pointer overwritten during reallocation
occurs when you overwrite the original pointer by the return value of
realloc()
. For
instance:
p = realloc(p,SIZE);
The function realloc()
returns a NULL
value when memory allocation fails. In the preceding code, because you overwrite
p
by the return of realloc()
, it
becomes NULL
when the reallocation operation fails. You lose
the connection between the original memory block and p
,
resulting in a memory leak.
When reallocating pointers, preserve the original pointer. For instance, you might use a temporary variable to store the reallocated memory.
#include <stdlib.h> //... void foo (int* ptrI, size_t new_size) { if (new_size == 0) { /* Handle error */ return; } ptrI = (int*)realloc (ptrI, new_size); //Noncompliant if (ptrI == NULL) { /* Handle error */ return; } }
Overwriting the pointer ptrI
by the
pointer returned by realloc
destroys the association
between ptrI
and the original memory block. If
realloc
fails, such overwriting might cause a memory
leak and data loss.
When reallocating a pointer, use a temporary variable to
hold the reallocated memory. Before assigning the temporary variable to
ptrI
, check it for NULL
value to
avoid memory leaks and data loss.
#include <stdlib.h> void foo (int* ptrI, size_t new_size) { int* temp; if (new_size == 0) { /* Handle error */ return; } temp = (int*)realloc (ptrI, new_size); if (temp == NULL) { /* Handle error */ return; }else{ ptrI = temp; } }
Check Information
Group: Rule 12. Error Handling (ERR) |
Version History
Introduced in R2019aR2021b: Checker flags unvalidated pointers from sensitive functions or memory leaks during memory reallocation
The checker is now raised when:
A sensitive function returns a pointer that is not validated before use. For instance:
Polyspace now raises a defect ifFILE *in; in = fmemopen (argv[1], strlen (argv[1]), "r");//Noncompliant
in
is not validated before it is used for accessing a file.A pointer is overwritten during memory reallocation. For instance:
Reallocation statements that overwrite the original pointer by the return value ofp = realloc(p,SIZE);
realloc()
might cause memory leaks and data loss if therealloc()
function fails.
See Also
External Websites
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.
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)