CWE Rule 131
Description
Rule Description
The software does not correctly calculate the size to be used when allocating a buffer, which could lead to a buffer overflow.
Polyspace Implementation
The rule checker checks for these issues:
Array access out of bounds
Memory allocation with tainted size
Pointer access out of bounds
Tainted sign change conversion
Tainted size of variable length array
Wrong type used in sizeof
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]
.
Memory allocation with tainted size
This issue occurs when a memory allocation function, such as calloc
or
malloc
, uses a size argument from an unsecure
source.
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.
Before allocating memory, check the value of your arguments to check that they do not exceed the bounds.
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> 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.
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; }
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.
Tainted sign change conversion
This issue occurs when values from unsecure sources are converted, implicitly or explicitly, from signed to unsigned values.
For example, functions that use size_t
as arguments implicitly convert the argument to an unsigned integer. Some functions that implicitly convert size_t
are:
bcmp memcpy memmove strncmp strncpy calloc malloc memalign
If you convert a small negative number to unsigned, the result is a large positive number. The large positive number can create security vulnerabilities. For example, if you use the unsigned value in:
Memory size routines — causes allocating memory issues.
String manipulation routines — causes buffer overflow.
Loop boundaries — causes infinite loops.
To avoid converting unsigned negative values, check that the value being converted is within an acceptable range. For example, if the value represents a size, validate that the value is not negative and less than the maximum value 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 <stdlib.h> #include <string.h> #include <stdio.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; void bug_taintedsignchange(void) { int size; scanf("%d",&size); char str[SIZE128] = ""; if (size<SIZE128) { memset(str, 'c', size); //Noncompliant } }
In this example, a char
buffer is created
and filled using memset
. The size argument to memset
is
an input argument to the function.
The call to memset
implicitly converts size
to
unsigned integer. If size
is a large negative number,
the absolute value could be too large to represent as an integer,
causing a buffer overflow.
size
One possible correction is to check if size
is
inside the valid range. This correction checks if size
is
greater than zero and less than the buffer size before calling memset
.
#include <stdlib.h> #include <string.h> #include <stdio.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; void corrected_taintedsignchange(void) { int size; scanf("%d",&size); char str[SIZE128] = ""; if (size>0 && size<SIZE128) { memset(str, 'c', size); } }
Tainted size of variable length array
This issue occurs when the size of a variable length array (VLA) is obtained from an unsecure source.
If an attacker changed the size of your VLA to an unexpected value, it can cause your program to crash or behave unexpectedly.
If the size is non-positive, the behavior of the VLA is undefined. Your program does not perform as expected.
If the size is unbounded, the VLA can cause memory exhaustion or stack overflow.
Validate your VLA size to make sure that it is positive and less than a maximum value.
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> #inclule<stdlib.h> #define LIM 40 long squaredSum(int size) { int tabvla[size]; //Noncompliant long res = 0; for (int i=0 ; i<LIM-1 ; ++i) { tabvla[i] = i*i; res += tabvla[i]; } return res; } int main(){ int size; scanf("%d",&size); //... long result = squaredSum(size); //... return 0; }
In this example, a variable length array size is based on an input argument. Because this input argument value is not checked, the size may be negative or too large.
One possible correction is to check the size variable before creating the variable length array. This example checks if the size is larger than 0 and less than 40, before creating the VLA
#include <stdio.h> #include <stdlib.h> #define LIM 40 long squaredSum(int size) { long res = 0; if (size>0 && size<LIM){ int tabvla[size]; for (int i=0 ; i<size || i<LIM-1 ; ++i) { tabvla[i] = i*i; res += tabvla[i]; } }else{ res = -1; } return res; } int main(){ int size; scanf("%d",&size); //... long result = squaredSum(size); //... return 0; }
Wrong type used in sizeof
This issue occurs when both of the following conditions hold:
You assign the address of a block of memory to a pointer, or transfer data between two blocks of memory. The assignment or copy uses the
sizeof
operator.For instance, you initialize a pointer using
malloc(sizeof(
or copy data between two addresses usingtype
))memcpy(
.destination_ptr
,source_ptr
, sizeof(type
))You use an incorrect type as argument of the
sizeof
operator. For instance:You might be using the pointer type instead of the type that the pointer points to. For example, to initialize a
pointer, you might be usingtype
*malloc(sizeof(
instead oftype
*))malloc(sizeof(
.type
))You might be using a completely unrelated type as
sizeof
argument. For example, to initialize a
pointer, you might be usingtype
*malloc(sizeof(
.anotherType
))
Irrespective of what type
stands
for, the expression sizeof(
always
returns a fixed size. The size returned is the pointer size on your
platform in bytes. The appearance of type
*)sizeof(
often
indicates an unintended usage. The error can cause allocation of a
memory block that is much smaller than what you need and lead to weaknesses
such as buffer overflows.type*
)
For instance, assume that structType
is a
structure with ten int
variables. If you initialize
a structType*
pointer using malloc(sizeof(structType*))
on
a 32-bit platform, the pointer is assigned a memory block of four
bytes. However, to be allocated completely for one structType
variable,
the structType*
pointer must point to a memory
block of sizeof(structType) = 10 * sizeof(int)
bytes.
The required size is much greater than the actual allocated size of
four bytes.
To initialize a
pointer,
replace type
*sizeof(
in
your pointer initialization expression with type
*)sizeof(
.type
)
#include <stdlib.h> void test_case_1(void) { char* str; str = (char*)malloc(sizeof(char*) * 5); //Noncompliant free(str); }
In this example, memory is allocated for the character pointer str
using
a malloc
of five char pointers. However, str
is
a pointer to a character, not a pointer to a character pointer. Therefore
the sizeof
argument, char*
,
is incorrect.
sizeof
ArgumentOne possible correction is to match the argument
to the pointer type. In this example, str
is a
character pointer, therefore the argument must also be a character.
#include <stdlib.h> void test_case_1(void) { char* str; str = (char*)malloc(sizeof(char) * 5); free(str); }
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 (한국어)