...
Code Block | ||
---|---|---|
| ||
int test(int x){
x--;
if(x < 0 || x > 10)
{
return 0;
}
else
{
static int y = test(x); //<--undefined behavior occurs here
return y;
}
}
|
The behavior observed from running this code under various compilers differs.
...
Code Block |
---|
terminate called after throwing an instance of '__gnu_cxx::recursive_init' what(): N9__gnu_cxx14recursive_initE Aborted (core dumped) |
Compliant Solution
...
Wiki Markup |
---|
In this compliant |
p
is declared with the same scope as str
, preventing p
from taking on an indeterminate value outside of this_is_OK()
.Code Block | ||
---|---|---|
| ||
void this_is_OK(void) {
const char str[] = "Everything OK";
const char *p = str;
/* ... */
}
/* p is inaccessible outside the scope of string str */
|
Compliant Solution (p
with File Scope)
If it is necessary for p
to be defined with file scope, it can be set to NULL
before str
is destroyed. This prevents p
from taking on an indeterminate value, although any references to p
must check for NULL
.
Code Block | ||
---|---|---|
| ||
const char *p;
void is_this_OK(void) {
const char str[] = "Everything OK?";
p = str;
/* ... */
p = NULL;
}
|
Noncompliant Code Example (Return Values)
In this example, the function init_array()
incorrectly returns a pointer to a local stack variable.
Code Block | ||
---|---|---|
| ||
char *init_array(void) {
char array[10];
/* Initialize array */
return array;
}
|
Some compilers generate a warning when a pointer to an automatic variable is returned from a function, as in this example. Compile your code at high warning levels and resolve any warnings (see MSC00-CPP. Compile cleanly at high warning levels).
Compliant Solution (Return Values)
Correcting this example depends on the intent of the programmer. If the intent is to modify the value of array
and have that modification persist outside of the scope of init_array()
, the desired behavior can be achieved by declaring array
elsewhere and passing it as an argument to init_array()
.
Code Block | ||
---|---|---|
| ||
void init_array(char array[]) {
/* Initialize array */
return;
}
int main(int argc, char *argv[]) {
char array[10];
init_array(array);
/* ... */
return 0;
}
|
Risk Assessment
solution, {{y}} is declared before being assigned a value. According to \[[ISO/IEC 14882-2003|AA. C++ References#ISO/IEC 14882-2003]\] Section 6.7.4, the initialization of {{y}} will have been completed at the end of the declaration and before the assignment of a value, thus removing the possibility of undefined behavior. |
Code Block | ||
---|---|---|
| ||
int test(int x){
x--;
if(x < 0 || x > 10)
{
return 0;
}
else
{
static int y;
y = test(x);
return y;
}
}
|
Risk Assessment
Recursively reentering a function during the initialization of one of its static objects can result in an attacker being able to cause a crash or denial of serviceReferencing an object outside of its lifetime can result in an attacker being able to run arbitrary code.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL30 DCL38-CPP | high med | probable unlikely | high low | P6 P8 | L2 L4 |
Automated Detection
The LDRA tool suite Version 7.6.0 can detect violations of this rule.
...