CWE Rule 125
Description
Rule Description
The software reads data past the end, or before the beginning, of the intended buffer.
Polyspace Implementation
The rule checker checks for these issues:
Array access out of bounds
Array access with tainted index
Buffer overflow from incorrect string format specifier
Destination buffer overflow in string manipulation
Destination buffer underflow in string manipulation
Invalid use of standard library memory routine
Invalid use of standard library string routine
Missing null in string array
Pointer access out of bounds
Pointer dereference with tainted offset
Possible misuse of sizeof
Tainted NULL or non-null-terminated string
Examples
Array access out of bounds
This issue occurs
when an array index falls outside the range [0...array_size-1]
during
array access.
Accessing an array 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.
The fix depends on the root cause of the defect. For instance, you accessed an array inside a loop and one of these situations happened:
The upper bound of the loop is too large.
You used an array index that is the same as the loop index instead of being one less than the loop index.
To fix the issue, you have to modify the loop bound or the array index.
Another reason why an array index can exceed array bounds is a prior conversion from signed to unsigned integers. The conversion can result in a wrap around of the index value, eventually causing the array index to exceed the array bounds.
Often the result details (or source code tooltips in Polyspace as You Code) 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 this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).
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:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.
#include <stdio.h> void fibonacci(void) { int i; int fib[10]; for (i = 0; i < 10; i++) { if (i < 2) fib[i] = 1; else fib[i] = fib[i-1] + fib[i-2]; } printf("The 10-th Fibonacci number is %i .\n", fib[i]); //Noncompliant /* Defect: Value of i is greater than allowed value of 9 */ }
The array fib
is assigned a size of 10. An array index
for fib
has allowed values of [0,1,2,...,9]
. The
variable i
has a value 10 when it comes out of the
for
-loop. Therefore, the printf
statement attempts to
access fib[10]
through i
.
One possible correction is to print fib[i-1]
instead of fib[i]
after the for
-loop.
#include <stdio.h> void fibonacci(void) { int i; int fib[10]; for (i = 0; i < 10; i++) { if (i < 2) fib[i] = 1; else fib[i] = fib[i-1] + fib[i-2]; } /* Fix: Print fib[9] instead of fib[10] */ printf("The 10-th Fibonacci number is %i .\n", fib[i-1]); }
The printf
statement accesses fib[9]
instead of
fib[10]
.
Array access with tainted index
This issue occurs when you access an array by using an index that is obtained from unsecure sources and which has not been validated.
The index might be outside the valid array range. If the tainted index is outside the array range, it can cause:
Buffer underflow/underwrite — writing to memory before the beginning of the buffer.
Buffer overflow — writing to memory after the end of a buffer.
Over-reading a buffer — accessing memory after the end of the targeted buffer.
Under-reading a buffer, or accessing memory before the beginning of the targeted buffer.
An attacker can use an invalid read or write operation create to problems in your program.
Before using the index to access the array, validate the index value to make sure that it is inside the array range.
By default, Polyspace® assumes that data from external sources are tainted. 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
.
#include <stdlib.h> #include <stdio.h> #define SIZE100 100 extern int tab[SIZE100]; static int tainted_int_source(void) { return strtol(getenv("INDEX"),NULL,10); } int taintedarrayindex(void) { int num = tainted_int_source(); return tab[num];//Noncompliant }
In this example, the index num
accesses the array tab
. The index num
is obtained from
an unsecure source and the function taintedarrayindex
does not check to
see if num
is inside the range of tab
.
One possible correction is to check that num
is
in range before using it.
#include <stdlib.h> #include <stdio.h> #define SIZE100 100 extern int tab[SIZE100]; static int tainted_int_source(void) { return strtol(getenv("INDEX"),NULL,10); } int taintedarrayindex(void) { int num = tainted_int_source(); if (num >= 0 && num < SIZE100) { return tab[num]; } else { return -1; } }
Buffer overflow from incorrect string format specifier
This issue occurs when the format specifier argument
for functions such as sscanf
leads to an overflow
or underflow in the memory buffer argument.
If the format specifier specifies a precision that is greater than the memory buffer size, an overflow occurs. Overflows can cause unexpected behavior such as memory corruption.
Use a format specifier that is compatible with the memory buffer size.
#include <stdio.h> void func (char *str[]) { char buf[32]; sscanf(str[1], "%33c", buf); //Noncompliant }
In this example, buf
can contain 32 char
elements.
Therefore, the format specifier %33c
causes a buffer
overflow.
One possible correction is to read a smaller number of elements into the buffer.
#include <stdio.h> void func (char *str[]) { char buf[32]; sscanf(str[1], "%32c", buf); }
Destination buffer overflow in string manipulation
This issue occurs when certain string manipulation functions write to their destination buffer argument at an offset greater than the buffer size.
For instance, when calling the function sprintf(char*
buffer, const char* format)
, you use a constant string format
of
greater size than buffer
.
Buffer overflow can cause unexpected behavior such as memory corruption or stopping your system. Buffer overflow also introduces the risk of code injection.
One possible solution is to use alternative functions to constrain the number of characters written. For instance:
If you use
sprintf
to write formatted data to a string, usesnprintf
,_snprintf
orsprintf_s
instead to enforce length control. Alternatively, useasprintf
to automatically allocate the memory required for the destination buffer.If you use
vsprintf
to write formatted data from a variable argument list to a string, usevsnprintf
orvsprintf_s
instead to enforce length control.If you use
wcscpy
to copy a wide string, usewcsncpy
,wcslcpy
, orwcscpy_s
instead to enforce length control.
Another possible solution is to increase the buffer size.
#include <stdio.h> void func(void) { char buffer[20]; char *fmt_string = "This is a very long string, it does not fit in the buffer"; sprintf(buffer, fmt_string); //Noncompliant }
In this example, buffer
can contain 20 char
elements
but fmt_string
has a greater size.
snprintf
Instead
of sprintf
One possible correction is to use the snprintf
function
to enforce length control.
#include <stdio.h> void func(void) { char buffer[20]; char *fmt_string = "This is a very long string, it does not fit in the buffer"; snprintf(buffer, 20, fmt_string); }
Destination buffer underflow in string manipulation
This issue occurs when certain string manipulation functions write to their destination buffer argument at a negative offset from the beginning of the buffer.
For instance, for the function sprintf(char* buffer,
const char* format)
, you obtain the buffer
from
an operation buffer = (char*)arr; ... buffer += offset;
. arr
is
an array and offset
is a negative value.
Buffer underflow can cause unexpected behavior such as memory corruption or stopping your system. Buffer underflow also introduces the risk of code injection.
If the destination buffer argument results from pointer arithmetic, see if you are decrementing a pointer. Fix the pointer decrement by modifying either the original value before decrement or the decrement value.
#include <stdio.h> #define offset -2 void func(void) { char buffer[20]; char *fmt_string ="Text"; sprintf(&buffer[offset], fmt_string); //Noncompliant }
In this example, &buffer[offset]
is at
a negative offset from the memory allocated to buffer
.
One possible correction is to change the value of offset
.
#include <stdio.h> #define offset 2 void func(void) { char buffer[20]; char *fmt_string ="Text"; sprintf(&buffer[offset], fmt_string); }
Invalid use of standard library memory routine
This issue occurs when a
memory library function is called with invalid arguments. For instance, the
memcpy
function copies to an array that cannot accommodate the
number of bytes copied.
Use of a memory library function with invalid arguments can result in issues such as buffer overflow.
The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) 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 this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).
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:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <string.h> #include <stdio.h> char* Copy_First_Six_Letters(void) { char str1[10],str2[5]; printf("Enter string:\n"); scanf("%9s",str1); memcpy(str2,str1,6); //Noncompliant /* Defect: Arguments of memcpy invalid: str2 has size < 6 */ return str2; }
The size of string str2
is
5, but six characters of string str1
are copied
into str2
using the memcpy
function.
One possible correction is to adjust the size
of str2
so that it accommodates the characters
copied with the memcpy
function.
#include <string.h> #include <stdio.h> char* Copy_First_Six_Letters(void) { /* Fix: Declare str2 with size 6 */ char str1[10],str2[6]; printf("Enter string:\n"); scanf("%9s",str1); memcpy(str2,str1,6); return str2; }
Invalid use of standard library string routine
This issue occurs when a string library function is called with invalid arguments.
The risk depends on the type of invalid arguments. For instance, using the
strcpy
function with a source argument larger than the
destination argument can result in buffer overflows.
The fix depends on the standard library function involved in the defect. In some cases, you can constrain the function arguments before the function call. For instance, if the strcpy
function:
char * strcpy(char * destination, const char* source)
strcpy
. In some cases, you can use an alternative function to avoid the error. For instance, instead of strcpy
, you can use strncpy
to control the number of bytes copied.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:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <string.h> #include <stdio.h> char* Copy_String(void) { char *res; char gbuffer[5],text[20]="ABCDEFGHIJKL"; res=strcpy(gbuffer,text); //Noncompliant /* Error: Size of text is less than gbuffer */ return(res); }
The string text
is larger
in size than gbuffer
. Therefore, the function strcpy
cannot
copy text
into gbuffer
.
One possible correction is to declare the destination
string gbuffer
with equal or larger size than the
source string text
.
#include <string.h> #include <stdio.h> char* Copy_String(void) { char *res; /*Fix: gbuffer has equal or larger size than text */ char gbuffer[20],text[20]="ABCDEFGHIJKL"; res=strcpy(gbuffer,text); return(res); }
Missing null in string array
This issue occurs when a string does not have enough
space to terminate with a null character '\0'
.
This defect applies only for projects in C.
A buffer overflow can occur if you copy a string to an array without assuming the implicit null terminator.
If you initialize a character array with a literal, avoid specifying the array bounds.
char three[] = "THREE";
If the issue occurs after initialization, you might have to increase the size of the array by one to account for the null terminator.
In certain circumstances, you might want to initialize the character array with a sequence of characters instead of a string. In this situation, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
void countdown(int i) { static char one[5] = "ONE"; static char two[5] = "TWO"; static char three[5] = "THREE"; //Noncompliant }
The character array three
has a size of 5 and 5 characters 'T'
, 'H'
, 'R'
, 'E'
, and 'E'
. There is no room for the null character at the end because three
is only five bytes large.
One possible correction is to change the array size to allow for the five characters plus a null character.
void countdown(int i) { static char one[5] = "ONE"; static char two[5] = "TWO"; static char three[6] = "THREE"; }
One possible correction is to initialize the string by leaving the array size blank. This initialization method allocates enough memory for the five characters and a terminating-null character.
void countdown(int i) { static char one[5] = "ONE"; static char two[5] = "TWO"; static char three[] = "THREE"; }
Pointer access out of bounds
This issue 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.
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.
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 (or source code tooltips in Polyspace as You Code) 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 this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).
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:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
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.
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.
Pointer dereference with tainted offset
This issue occurs when a pointer dereference uses an offset variable from an unknown or unsecure source.
This check focuses on dynamically allocated buffers. For static
buffer offsets, see Array access with tainted index
.
The index might be outside the valid array range. If the tainted index is outside the array range, it can cause:
Buffer underflow/underwrite, or writing to memory before the beginning of the buffer.
Buffer overflow, or writing to memory after the end of a buffer.
Over reading a buffer, or accessing memory after the end of the targeted buffer.
Under-reading a buffer, or accessing memory before the beginning of the targeted buffer.
An attacker can use an invalid read or write to compromise your program.
Validate the index before you use the variable to access the pointer. Check to make sure that the variable is inside the valid range and does not overflow.
By default, Polyspace assumes that data from external sources are tainted. 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
.
#include <stdio.h> #include <stdlib.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; extern void read_pint(int*); int taintedptroffset(void) { int offset; scanf("%d",&offset); int* pint = (int*)calloc(SIZE10, sizeof(int)); int c = 0; if(pint) { /* Filling array */ read_pint(pint); c = pint[offset];//Noncompliant free(pint); } return c; }
In this example, the function initializes an integer
pointer pint
. The pointer is dereferenced using the input index
offset
. The value of offset
could be outside the
pointer range, causing an out-of-range error.
One possible correction is to validate the value of offset
. Continue with
the pointer dereferencing only if offset
is inside the valid range.
#include <stdlib.h> #include <stdio.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; extern void read_pint(int*); int taintedptroffset(void) { int offset; scanf("%d",&offset); int* pint = (int*)calloc(SIZE10, sizeof(int)); int c = 0; if (pint) { /* Filling array */ read_pint(pint); if (offset>0 && offset<SIZE10) { c = pint[offset]; } free(pint); } return c; }
Possible misuse of sizeof
This issue occurs
when Polyspace
Bug Finder™ detects possibly unintended results from
the use of sizeof
operator. For instance:
You use the
sizeof
operator on an array parameter name, expecting the array size. However, the array parameter name by itself is a pointer. Thesizeof
operator returns the size of that pointer.You use the
sizeof
operator on an array element, expecting the array size. However, the operator returns the size of the array element.The size argument of certain functions such as
strncmp
orwcsncpy
is incorrect because you used thesizeof
operator earlier with possibly incorrect expectations. For instance:In a function call
strncmp(string1, string2, num)
,num
is obtained from an incorrect use of thesizeof
operator on a pointer.In a function call
wcsncpy(destination, source, num)
,num
is the not the number of wide characters but a size in bytes obtained by using thesizeof
operator. For instance, you usewcsncpy(destination, source, sizeof(destination) - 1)
instead ofwcsncpy(destination, source, (sizeof(desintation)/sizeof(wchar_t)) - 1)
.
Incorrect use of the sizeof
operator can
cause the following issues:
If you expect the
sizeof
operator to return array size and use the return value to constrain a loop, the number of loop runs are smaller than what you expect.If you use the return value of
sizeof
operator to allocate a buffer, the buffer size is smaller than what you require. Insufficient buffer can lead to resultant weaknesses such as buffer overflows.If you use the return value of
sizeof
operator incorrectly in a function call, the function does not behave as you expect.
Possible fixes are:
Do not use the
sizeof
operator on an array parameter name or array element to determine array size.The best practice is to pass the array size as a separate function parameter and use that parameter in the function body.
Use the
sizeof
operator carefully to determine the number argument of functions such asstrncmp
orwcsncpy
. For instance, for wide string functions such aswcsncpy
, use the number of wide characters as argument instead of the number of bytes.
#define MAX_SIZE 1024 void func(int a[MAX_SIZE]) { int i; for (i = 0; i < sizeof(a)/sizeof(int); i++) //Noncompliant { a[i] = i + 1; } }
In this example, sizeof(a)
returns the size
of the pointer a
and not the array size.
One possible correction is to use another means to determine the array size.
#define MAX_SIZE 1024 void func(int a[MAX_SIZE]) { int i; for (i = 0; i < MAX_SIZE; i++) { a[i] = i + 1; } }
Tainted NULL or non-null-terminated string
This issue occurs when strings from unsecure sources are used in string manipulation routines
that implicitly dereference the string buffer, for instance, strcpy
or
sprintf
.
Tainted NULL or non-null-terminated string raises no
defect for a string returned from a call to scanf
-family variadic
functions. Similarly, no defect is raised when you pass the string with a
%s
specifier to printf
-family variadic
functions.
If a string is from an unsecure source, it is possible that an attacker manipulated the string or pointed the string pointer to a different memory location.
If the string is NULL, the string routine cannot dereference the string, causing the program to crash. If the string is not null-terminated, the string routine might not know when the string ends. This error can cause you to write out of bounds, causing a buffer overflow.
Validate the string before you use it. Check that:
The string is not NULL.
The string is null-terminated
The size of the string matches the expected size.
By default, Polyspace assumes that data from external sources are tainted. 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
.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define SIZE128 128 #define MAX 40 extern void print_str(const char*); void warningMsg(void) { char userstr[MAX]; read(0,userstr,MAX); char str[SIZE128] = "Warning: "; strncat(str, userstr, SIZE128-(strlen(str)+1));//Noncompliant print_str(str); }
In this example, the string str
is concatenated
with the argument userstr
. The value of userstr
is
unknown. If the size of userstr
is greater than
the space available, the concatenation overflows.
One possible correction is to check the size of userstr
and
make sure that the string is null-terminated before using it in strncat
.
This example uses a helper function, sansitize_str
,
to validate the string. The defects are concentrated in this function.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define SIZE128 128 #define MAX 40 extern void print_str(const char*); int sanitize_str(char* s) { int res = 0; if (s && (strlen(s) > 0)) { // Noncompliant-TAINTED_STRING only flagged here // - string is not null // - string has a positive and limited size // - TAINTED_STRING on strlen used as a firewall res = 1; } return res; } void warningMsg(void) { char userstr[MAX]; read(0,userstr,MAX); char str[SIZE128] = "Warning: "; if (sanitize_str(userstr)) strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); }
Another possible correction is to call function errorMsg
and
warningMsg
with specific strings.
#include <stdio.h> #include <string.h> #include <stdlib.h> #define SIZE128 128 extern void print_str(const char*); void warningMsg(char* userstr) { char str[SIZE128] = "Warning: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } void errorMsg(char* userstr) { char str[SIZE128] = "Error: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } int manageSensorValue(int sensorValue) { int ret = sensorValue; if ( sensorValue < 0 ) { errorMsg("sensor value should be positive"); exit(1); } else if ( sensorValue > 50 ) { warningMsg("sensor value greater than 50 (applying threshold)..."); sensorValue = 50; } return sensorValue; }
Check Information
Category: Memory Buffer Errors |
Version History
Introduced in R2023a
See Also
External Websites
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 (한국어)