Passing narrow string arguments to wide string functions or wide string arguments to narrow string functions can lead to unexpected and undefined behavior. 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.
#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.
#include <wchar.h>
void
func(
void
) {
char
narrow_str1[] =
"01234567890123456789"
;
char
narrow_str2[] =
"0000000000"
;
wcsncpy(narrow_str2,
narrow_str1, 10);
}
|
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.
#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:
#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 determines the number of characters that precede the
terminating null character. However, wide characters can contain
null bytes, particularly 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 terminating null wide character:
#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;
}
|