Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Strings must contain a null-termination character at or before the address of the last element of the array before they can be safely passed as arguments to standard string-handling functions, such as strcpy() or strlen(). This is because these functions, as well as other string-handling functions defined by the C Standard [ISO/IEC 9899:2011], depend on the existence of a null-termination character to determine the length of a string. Similarly, strings must be null-terminated before iterating on a character array where the termination condition of the loop depends on the existence of a null-termination character within the memory allocated for the string, as in the following example:

Code Block
langc
size_t i;
void func(void) {
  char ntbs[16];

/* ... */
for (size_t i = 0; i < sizeof(ntbs); ++i) {
    if (ntbs[i] == '\0') {
      break;
  /* ... */}
  }

Failure to properly terminate null-terminated byte strings can result in buffer overflows and other undefined behavior.

...

Code Block
bgColor#FFcccc
langc
#include <string.h>
 
enum { NTBS_SIZE = 32 };
 
void func(void) {
  char ntbs[NTBS_SIZE];

  ntbs[sizeof(ntbs) - 1] = '\0';
  strncpy(ntbs, source, sizeof(ntbs));
}

In the second noncompliant code example, memset() is used to clear the destination buffer; unfortunately, the third argument incorrectly specifies the size of the destination array [Schwarz 2005]:

Code Block
bgColor#FFcccc
langc
#include <string.h>
 
enum { NTBS_SIZE = 32 };
 
void func(void) {
  char ntbs[NTBS_SIZE];

  memset(ntbs, 0, sizeof(ntbs) - 1);
  strncpy(ntbs, source, sizeof(ntbs) - 1);
}

Compliant Solution (Truncation)

...

Code Block
bgColor#ccccff
langc
#include <string.h>
 
enum { NTBS_SIZE = 32 };
 
void func(void) {
  char ntbs[NTBS_SIZE];

  strncpy(ntbs, source, sizeof(ntbs) - 1);
  ntbs[sizeof(ntbs) - 1] = '\0';
}

Compliant Solution (Copy without Truncation)

...

Code Block
bgColor#ccccff
langc
#include <string.h>
 
enum { NTBS_SIZE = 32 };
 
void func(void) {
  char *source = "0123456789abcdef";
  char ntbs[NTBS_SIZE];

/* ... */
if (source) {
    if (strlen(source) < sizeof(ntbs)) {
      strcpy(ntbs, source);
    }
  else {
      /* Handle string too large condition. */
    }
  }
 else {
    /* Handle NULL string condition. */
  }
}

Compliant Solution (strncpy_s(), C11 Annex K)

...

Code Block
bgColor#ccccff
langc
#define __STDC_WANT_LIB_EXT1__
#include <string.h>
  
enum { NTBS_SIZE = 32 };
  
void func(void) {
  char *source = "0123456789abcdef";
  char a[NTBS_SIZE];

/* ... */
if (source) {
    errno_t err = strncpy_s(a, sizeof(a), source, 5);
    if (err != 0) {
      /* Handle error */
    }
  }
 else {
    /* Handle NULL string condition. */
  }

}

Noncompliant Code Example (realloc())

...

Code Block
bgColor#ffcccc
langc
#include <stdlib.h>
 
char *cur_msg = NULL;
size_t cur_msg_size = 1024;

/* ... */

 
void lessen_memory_usage(void) {
  char *temp;
  size_t temp_size;

  /* ... */

  if (cur_msg != NULL) {
    temp_size = cur_msg_size / 2 + 1;
    temp = realloc(cur_msg, temp_size);
    if (temp == NULL) {
      /* Handle error condition */
    }
    cur_msg = temp;
    cur_msg_size = temp_size;
  }
}

/* ... */

Because realloc() does not guarantee that the string is properly null-terminated, any subsequent operation on cur_msg that assumes a null-termination character may result in undefined behavior.

...

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
 
char *cur_msg = NULL;
size_t cur_msg_size = 1024;

/* ... */

void lessen_memory_usage(void) {
  char *temp;
  size_t temp_size;

  /* ... */

  if (cur_msg != NULL) {
    temp_size = cur_msg_size / 2 + 1;
    temp = realloc(cur_msg, temp_size);
    if (temp == NULL) {
      /* Handle error condition */
    }
    cur_msg = temp;
    cur_msg_size = temp_size;

    /* Ensure string is null-terminated. */
    cur_msg[cur_msg_size - 1] = '\0';
  }
}

/* ... */

Risk Assessment

Failure to properly null-terminate strings can result in buffer overflows and the execution of arbitrary code with the permissions of the vulnerable process. Null-termination errors can also result in unintended information disclosure.

...

K.7.1.4, "The strncpy_s Function"
CERT C++ Secure Coding StandardSTR32-CPP. Null-terminate character arrays as requiredISO/IEC 9899:2011
ISO/IEC TR 24772:2013String Termination [CMJ]
ISO/IEC TS 17961 (Draft)Passing a non-null-terminated character sequence to a library function that expects a string [strmod]
MITRE CWECWE-119, Failure to constrain operations within the bounds of an allocated memory buffer
CWE-170, Improper null termination

Bibliography

[ISO/IEC 9899:2011] Subclause K.7.1.4, "The strncpy_s function"
[Schwarz 2005] 
[Seacord 2013] Chapter 2, "Strings" 
[Viega 2005]Section 5.2.14, "Miscalculated NULL Termination"

 

...