Versions Compared

Key

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

Passing narrow string arguments to wide string functions or wide string arguments to narrow string functions can lead to unexpected and undefined behavior 151. Scaling problems are likely because of the difference in size between wide and narrow characters. (See ARR39-C. Do not add or subtract a scaled integer to a pointer.) Because wide strings are terminated by a null wide character and can contain null bytes, determining the length is also problematic.

Because wchar_t and char are distinct types, many compilers will produce a warning diagnostic if an inappropriate function is used. (See MSC00-C. Compile cleanly at high warning levels.)

Noncompliant Code Example (Wide Strings with Narrow String Functions) 

This noncompliant code example incorrectly uses the strncpy() function in an attempt to copy up to 10 wide characters. However, because wide characters can contain null bytes, the copy operation may end earlier than anticipated, resulting in the truncation of the wide string

Wide characters will contain null bytes if taken from the ASCII character set. As a result, using narrow character functions that rely on null-byte termination can lead to obtuse behavior. Likewise, a narrow character string that is properly null-terminated might not be considered so in a wide character function. Improper use of narrow and wide character strings could result in buffer overflows or data truncation.

Noncompliant Code Example (Using strncpy() instead of wcsncpy())

This example uses strncpy(), which copies, at most, 10 wide characters but will stop copying after it encounters a null byte. Because wide characters can contain null bytes, the code can stop copying prematurely. It is important to recognize that many narrow string functions are byte functions and so can terminate prematurely.

Code Block
bgColor#ffcccc
langc
#include <stddef.h>
#include <string.h>
 
void func(void) {
  wchar_t wide_str1[]  = L"0123456789";
  wchar_t wide_str2[] =  L"0000000000";

  strncpy(wide_str2, wide_str1, 10);
}

Noncompliant Code Example (

...

Narrow Strings with Wide String Functions)

This noncompliant code example incorrectly invokes the wcsncpy() function to copy up to 10 wide characters from narrow_str1 to narrow_str2. Because narrow_str2 is a narrow string, it has insufficient memory to store the result of the copy and the copy will result in a buffer overflow

In most implementations, wide characters span multiple narrow characters. The wcsncpy() function copies, at most, 10 wide characters, which is greater than the number of bytes allocated to narrow_str1. As a result, it will write the first 10 bytes of narrow_str1 into narrow_str2 and then continue padding with L'\0' null wide characters until 10 wide characters have been written.

Note that wcsncpy() does not perform null termination if the source string contains more wide characters than the destination. Consequently, it is possible for an attacker to exploit such a vulnerability by passing a maliciously crafted string to wcsncpy(). If the code is intended to copy a certain number of bytes, it can overflow the buffer by writing multiple bytes because wcsncpy() measures copying by wide characters, not by bytes.

Code Block
bgColor#ffcccc
langc
#include <wchar_t.h>
 
void func(void) {
  char narrow_str1[] = "012345678901234567890123456789";
  char narrow_str2[] = "0000000000";

  wcsncpy(narrow_str2, narrow_str1, 10);
}

Implementation Details

The C Standard recognizes wchar_t[] and char[] as distinct types. As a result, many compilers will produce a warning if the inappropriate function is used. For example, the following warnings were generated when the second noncompliant example was compiled with no flags in GCC on a Linux i686 platform:

Code Block
warning: passing arg 1 of `wcsncpy' from incompatible pointer type
warning: passing arg 2 of `wcsncpy' from incompatible pointer type

Similar warnings were issued by the compiler for the first noncompliant example with respect to the arguments of the strncpy function instead. Because these are just warnings, the compiled code can still be run. When run on the i686 Linux platform, both noncompliant code examples exhibited buffer overflows.

Compliant Solution

This compliant solution uses the proper-width functions. Using wcsncpy() for wide character strings and strncpy() for narrow character strings ensures that data is not truncated and buffer overflow does not occur.

Code Block
bgColor#ccccff
langc
#include <stddef.h>
#include <string.h>
#include <wchar.h>
 
void func(void) {
  wchar_t wide_str1[] = L"0123456789";
  wchar_t wide_str2[] = L"0000000000";
  /* Use of proper-width function */ 
  wcsncpy(wide_str2, wide_str1, 10);

  char narrow_str1[] = "0123456789";
  char narrow_str2[] = "0000000000";
  /* Use of proper-width function */ 
  strncpy(narrow_str2, narrow_str1, 10);
}

Noncompliant Code Example (strlen())

In this noncompliant code example, the strlen() function is used to determine the size of a wide character string:

Code Block
bgColor#FFcccc
langc
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
 
void func(void) {
  wchar_t wide_str1[] = L"0123456789";
  wchar_t *wide_str2 = (wchar_t *)malloc(strlen(wide_str1) + 1);
  if (wide_str2 == NULL) {
    /* Handle error */
  }

  /* ... */
  free(wide_str2);
  wide_str2 = NULL;
}

The strlen() function counts determines the number of characters in a null-terminated byte string preceding that precede the terminating null bytecharacter. However, wide characters can contain null bytes, particularly when taken from when expressing characters from the ASCII character set, as in this example. As a result, the strlen() function will return the number of bytes preceding the first null byte in the wide string. 

Compliant Solution

This compliant solution correctly calculates the number of bytes required to contain a copy of the wide string (, including the termination terminating null wide character):

Code Block
bgColor#ccccff
langc
#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>
 
void func(void) {
  wchar_t wide_str1[] = L"0123456789";
  wchar_t *wide_str2 = (wchar_t *)malloc(
    (wcslen(wide_str1) + 1) * sizeof(wchar_t));
  if (wide_str2 == NULL) {
    /* Handle error */
  }
  /* ... */

  free(wide_str2);
  wide_str2 = NULL;
}

Risk Assessment

Failure to use the proper-width string functions can lead to buffer overflows and the execution of arbitrary code by an attackerConfusing narrow and wide character strings can result in buffer overflows, data truncation, and other defects.

Rule

Severity

Likelihood

Remediation Cost

Detectable

Repairable

Priority

Level

STR38-C

High

Likely

Low

Yes

No

P27

P18

L1

Automated Detection

Modern compilers recognize the difference between a char * and a wchar_t *, so compiling code that violates this rule will generate warnings. It is feasible to have automated software that recognizes functions of improper width and replaces them with functions of proper width (that is, software that uses wcsncpy() when it recognizes that the parameters are of type wchar_t *).

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V
wide-narrow-string-cast
wide-narrow-string-cast-implicit
Partially checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-STR38Fully implemented
Clang
Include Page
Clang_V
Clang_V
-Wincompatible-pointer-types
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.MEM.BO
LANG.MEM.TBA

Buffer Overrun
Tainted Buffer Access

Coverity
Include Page
Coverity_V
Coverity_V

PW

Implemented
Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

premium-cert-str38-c
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C0432

C++0403 


Klocwork
Include Page
Klocwork_V
Klocwork_V

CXX.DIFF.WIDTH.STR_AND_FUNC


Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_C-STR38-a
Do not confuse narrow and wide character strings and functions
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

2454, 2480, 2481

Partially supported: reports illegal conversions involving pointers to char or wchar_t as well as byte/wide-oriented stream inconsistencies

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule STR38-C

Checks for misuse of narrow or wide character string (rule fully covered)

RuleChecker

Include Page
RuleChecker_V
RuleChecker_V

wide-narrow-string-cast
wide-narrow-string-cast-implicit
Partially checked
Security Reviewer - Static Reviewer

Include Page
Security Reviewer - Static Reviewer_V
Security Reviewer - Static Reviewer_V

UNSAFE_02Fully implemented
TrustInSoft Analyzer

Include Page
TrustInSoft Analyzer_V
TrustInSoft Analyzer_V

pointer arithmeticPartially verified.


Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Bibliography

[ISO/IEC 9899:2024]7.26.2.5, "The strncpy Function"
7.31.4.2.2, "The wcsncpy Function"


...

Image Modified Image Modified Image Modified