If control reaches the closing curly brace (}
) of a non-void function without evaluating a return
statement, using the return value of the function call is undefined behavior 88 .
This rule is related to MSC01-C. Strive for logical completeness because both guidelines are intended to ensure that programs properly handle all possible conditions.
Noncompliant Code Example
In this noncompliant code example, control reaches the end of the checkpass()
function when the two strings passed to strcmp()
are not equal, resulting in undefined behavior. Many compilers will generate code for the checkpass()
function, returning various values along the execution path where no return
statement is defined.
#include <string.h> int checkpass(const char *password) { if (strcmp(password, "pass") == 0) { return 1; } } void func(const char *userinput) { if (checkpass(userinput)) { printf("Success\n"); } }
This error is frequently diagnosed by compilers. (See MSC00-C. Compile cleanly at high warning levels.)
Compliant Solution
This compliant solution ensures that the checkpass()
function always returns a value:
#include <string.h> int checkpass(const char *password) { if (strcmp(password, "pass") == 0) { return 1; } return 0; } void func(const char *userinput) { if (checkpass(userinput)) { printf("Success!\n"); } }
Noncompliant Code Example
In this noncompliant code example, control reaches the end of the getlen()
function when input
does not contain the integer delim
. Because the potentially undefined return value of getlen()
is later used as an index into an array, a buffer overflow may occur.
size_t getlen(const int *input, size_t maxlen, int delim) { for (size_t i = 0; i < maxlen; ++i) { if (input[i] == delim) { return i; } } } void func(int userdata) { size_t i; int data[] = { 1, 1, 1 }; i = getlen(data, sizeof(data), 0); data[i] = userdata; }
Implementation Details
When the following is compiled with -Wall
on most versions of the GCC compiler, the following warning is generated:
example.c: In function 'getlen': example.c:12: warning: control reaches end of non-void function
When the following program is compiled and run with GCC 4.4.3 on Linux, the getlen()
function returned 5, causing an out-of-bounds write to the data
array:
#include <stdio.h> size_t getlen(const int *input, size_t maxlen, int delim) { for (size_t i = 0; i < maxlen; ++i) { if (input[i] == delim) { return i; } } } int main(int argc, char **argv) { size_t i; int data[] = { 1, 1, 1 }; i = getlen(data, sizeof(data), 0); printf("Returned: %zu\n", i); data[i] = 0; return 0; }
Compliant Solution
This compliant solution changes the interface of getlen()
to store the result in a user-provided pointer and return an error code to indicate any error conditions. The best method for handling this type of error is specific to the application and the type of error. (See ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy for more on error handling.)
int getlen(const int *input, size_t maxlen, int delim, size_t *result) { for (size_t i = 0; i < maxlen; ++i) { if (input[i] == delim) { if (result != NULL) { *result = i; } return 0; } } return -1; } void func(int userdata) { size_t i; int data[] = {1, 1, 1}; if (getlen(data, sizeof(data), 0, &i) != 0) { /* Handle error */ } else { data[i] = userdata; } }
Exceptions
MSC37-EX1: According to the C Standard, subclause 5.1.2.2.3, paragraph 1 [ISO/IEC 9899:2011], "reaching the }
that terminates the main function returns a value of 0." As a result, it is permissible for control to reach the end of the main function without executing a return statement.
Risk Assessment
Using the return value from a non-void function where control reaches the end of the function can lead to a buffer overflow vulnerability as well as other unexpected program behaviors.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC37-C | High | Unlikely | Low | P9 | L2 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Bibliography
[ISO/IEC 9899:2011] | Subclause 5.1.2.2.3, "Program Termination" |