Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added an exception, updated code examples; reviewed.

If control reaches the closing curly brace (}) of a nonvoid non-void function without evaluating a return statement, using the return value of the function call causes undefined behavior. See undefined behavior 88 in Annex J, subclause J.2 of the C Standard [ISO/IEC 9899:2011].

This rule is related to MSC01-C. Strive for logical completeness because both practices are intended to ensure that programs properly handle all possible conditions.

...

Code Block
bgColor#ffcccc
langc
#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.)

...

Code Block
bgColor#ccccff
langc
#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 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.

Code Block
bgColor#ffcccc
langc
size_t getlen(const int *input, size_t maxlen, int delim) {
  for (size_t i;
  for (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:

...

Code Block
bgColor#ffcccc
langc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

size_t getlen(const int *input, size_t maxlen, int delim) {
  for (size_t i;
  for (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: %d%z\n", i);
  data[i] = 0;

  return EXIT_SUCCESS0;

}

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.)

Code Block
bgColor#ccccff
langc
int getlen(const int *input, size_t maxlen, int delim, size_t *result) {
  for (size_t i;
  for (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

...; reaching the } that terminates the main function returns a value of 0.

Thus, 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 nonvoid 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]Annex J, subclause J.2, "Undefined behavior"