Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: updated for consistency with TS 17961

...

In the common case, on implementations that make use of a program stack, this value defaults to whichever values are currently stored in stack memory. Uninitialized memory often contains—but is not guaranteed to contain—zeros. Uninitialized memory has indeterminate value, which for objects of some types can be a trap representation. Reading uninitialized memory by an lvalue of a type other than unsigned char is undefined behavior, (see undefined behavior 10 in  and undefined behavior 12 in Annex J of the C Standard), it can cause a program to behave in an unexpected manner and provide an avenue for attack.

...

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
#include <ctype.h>
#include <string.h>

int do_auth(void) {
  char *username;
  char *password;

  /* Get username and password from user, return -1 if invalid */
}

void report_error(const char *msg) {
  const char *error_log;
  char buffer[24];

  sprintf(buffer, "Error: %s", error_log);
  printf("%s\n", buffer);
}

int main(void) {
  if (do_auth() == -1) {
    report_error("Unable to login");
  }
  return 0;
}

Noncompliant Code Example

In this noncompliant example,  the array elements a[n..2n] are uninitialized when they are accessed in the for loop.

Code Block
bgColor#ffcccc
langc
void g(double *a, size_t n) {
  a = (double *)realloc(a, (n * 2 + 1) * sizeof(double));
  if (a != NULL) {
    for (size_t i = 0; i != n * 2 + 1; ++i) {
      if (a[i] < 0) {
        a[i] = -a[i];  /* violation */
      }
    }
 
    /* ... */
    free(a);
  }
}

Compliant Solution 

In this compliant example,  the array elements a[n..2n] are initialized to 0 when they are accessed in the for loop.

Code Block
bgColor#ccccff
langc
void g(double *a, size_t n) {
  a = (double *)calloc(a, (n * 2 + 1) * sizeof(double));
  if (a != NULL) {
    for (size_t i = 0; i != n * 2 + 1; ++i) {
      if (a[i] < 0) {
        a[i] = -a[i]; 
      }
    }
 
    /* ... */
    free(a);
  }
}

Noncompliant Code Example

In this noncompliant code example, the report_error() function has been modified so that error_log is properly initialized.

...

This solution is still problematic because a buffer overflow will occur if the null-terminated byte string referenced by msg is greater than 17 bytes, including the NULL terminator. The solution also makes use of a "magic number," which should be avoided. (See DCL06-C. Use meaningful symbolic constants to represent literal values.)

Compliant Solution

In this compliant solution, the magic number is abstracted, and the buffer overflow is eliminated.

Code Block
bgColor#ccccff
langc
enum {max_buffer = 24};

void report_error(const char *msg) {
  const char *error_log = msg;
  char buffer[max_buffer];

  snprintf(buffer, sizeof(buffer), "Error: %s", error_log);
  printf("%s\n", buffer);
}

Compliant Solution

A much simpler, less error prone, and better-performing compliant solution is shown here:

...