Many library functions accept a string or wide string argument with the constraint that the string they receive is properly null-terminated. Passing a character sequence or wide character sequence that is not null-terminated to such a function can result in accessing memory that is outside the bounds of the object. Do not pass a character sequence or wide character sequence that is not null-terminated to a library function that expects a string or wide string argument.
...
This code example is noncompliant because the character sequence c_str
will not be null-terminated when passed as an argument to printf()
(see STR11-C. Do not specify the bound of a character array initialized with a string literal): on how to properly initialize character arrays).
Code Block |
---|
|
#include <stdio.h>
void func(void) {
char c_str[3] = "abc";
printf("%s\n", c_str);
}
|
...
Code Block |
---|
|
#include <stdlib.h>
#include <wchar.h>
wchar_t *cur_msg = NULL;
size_t cur_msg_size = 1024;
size_t cur_msg_len = 0;
void lessen_memory_usage(void) {
wchar_t *temp;
size_t temp_size;
/* ... */
if (cur_msg != NULL) {
temp_size = cur_msg_size / 2 + 1;
temp = realloc(cur_msg, temp_size * sizeof(wchar_t));
//* temp &and cur_msg may mightno notlonger be null-terminated */
if (temp == NULL) {
/* Handle error */
}
cur_msg = temp;
cur_msg_size = temp_size;
cur_msg_len = wcslen(cur_msg);
}
} |
...
Code Block |
---|
|
#include <stdlib.h>
#include <wchar.h>
wchar_t *cur_msg = NULL;
size_t cur_msg_size = 1024;
size_t cur_msg_len = 0;
void lessen_memory_usage(void) {
wchar_t *temp;
size_t temp_size;
/* ... */
if (cur_msg != NULL) {
temp_size = cur_msg_size / 2 + 1;
temp = realloc(cur_msg, temp_size * sizeof(wchar_t));
//* temp &and cur_msg may mightno notlonger be null-terminated */
if (temp == NULL) {
/* Handle error */
}
cur_msg = temp;
//* Properly null-terminate cur_msg now properly null-terminated*/
cur_msg[temp_size - 1] = L'\0';
cur_msg_size = temp_size;
cur_msg_len = wcslen(cur_msg);
}
} |
Noncompliant Code Example (strncpy()
)
While Although the strncpy()
function takes a string as input, it does not guarantee that the resulting value is still null-terminated. In the following noncompliant code example, if no null character is contained in the first n
characters of the source
array, the result will not be null-terminated. Passing a non-null-terminated character sequence to strlen()
results in is undefined behavior:.
Code Block |
---|
|
#include <string.h>
enum { STR_SIZE = 32 };
size_t func(const char *source) {
char c_str[STR_SIZE];
c_str[sizeof(c_str) - 1] = '\0';
strncpy(c_str, source, sizeof(c_str));
return strlen(c_str);
}
|
Compliant Solution (Truncation)
The correct solution depends on This compliant solution is correct if the programmer's intent. If the intent is to truncate a string, this solution can be usedthe string:
Code Block |
---|
|
#include <string.h>
enum { STR_SIZE = 32 };
size_t func(const char *source) {
char c_str[STR_SIZE];
strncpy(c_str, source, sizeof(c_str) - 1);
c_str[sizeof(c_str) - 1] = '\0';
return strlen(c_str);
} |
Compliant Solution (
...
Truncation, strncpy_s())
The C Standard, Annex K strncpy_s()
function can also be used to copy with truncation. The strncpy_s()
function copies up to n
characters from the source array to a destination array. If no null character was copied from the source array, then the n
th position in the destination array is set to a null character, guaranteeing that the resulting string is null-terminated.
Code Block |
---|
|
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
enum { STR_SIZE = 32 };
size_t func(const char *source) {
char c_stra[STR_SIZE];
if (source) {
if (strlen(source) < sizeof(c_str)) {
errno_t err = strncpy_s(
a, strcpy(c_strsizeof(a), source, strlen(source)
);
if (err }!= else0) {
/* Handle string-too-largeerror */
}
} else {
/* Handle null pointer */
}
return strlen(c_str_s(s, sizeof(a));
}
|
Compliant Solution (
...
Copy without Truncation)
If the programmer's intent is to copy without truncation, this compliant solution copies the data and guarantees that the resulting array is null-terminated. If the string cannot be copied, it is handled as an error condition.The C11 Annex K strncpy_s()
function copies up to n
characters from the source array to a destination array. If no null character was copied from the source array, then the n
th position in the destination array is set to a null character, guaranteeing that the resulting string is null-terminated.
Code Block |
---|
|
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
enum { STR_SIZE = 32 };
size_t func(const char *source) {
char ac_str[STR_SIZE];
if (source) {
errno_t err = strncpy_s(a, sizeof(a), source, 5if (strlen(source) < sizeof(c_str)) {
strcpy(c_str, source);
if (err != 0)} else {
/* Handle errorstring-too-large */
}
} else {
/* Handle null pointer */
}
return strlen_s(s, sizeof(a)(c_str);
} |
Risk Assessment
Failure to properly null-terminate a character sequence that is passed to a library function that expects a string 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.
...
Related Guidelines
Bibliography
...