问题
The following program
// Code has taken from http://ideone.com/AXClWb
#include <stdio.h>
#include <string.h>
#define SIZE1 5
#define SIZE2 10
#define SIZE3 15
int main(void){
char a[SIZE1] = "Hello";
char b[SIZE2] = " World";
char res[SIZE3] = {0};
for (int i=0 ; i<SIZE1 ; i++){
res[i] = a[i];
}
strcat(res, b);
printf("The new string is: %s\n",res);
return 0;
}
has well defined behavior. As per the requirement, source string b
is null terminated. But what would be the behavior if the line
char res[SIZE3] = {0}; // Destination string
is replaced with
char res[SIZE3];
Does standard says explicitly about the destination string to be null terminated too?
回答1:
TL;DR Yes.
Since this is a language-lawyer question, let me add my two cents to it.
Quoting C11
, chapter §7.24.3.1/2 (emphas is mine)
char *strcat(char * restrict s1,const char * restrict s2);
The
strcat
function appends a copy of the string pointed to bys2
(including the terminating null character) to the end of the string pointed to bys1
. The initial character ofs2
overwrites the null character at the end ofs1
.[...]
and, by definition, a string is null-terminated, quoting §7.1.1/1
A string is a contiguous sequence of characters terminated by and including the first null character.
So, if the source char
array is not null-terminated (i.e., not a string), strcat()
may very well go beyond the bounds in search of the end which invokes undefined behavior.
As per your question, char res[SIZE3];
being an automatic local variable, will contain indeterminate value, and if used as the destination of strcat()
, will invoke UB.
回答2:
I think man explicitly says that
Description
The strcat() function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable; buffer overruns are a favorite avenue for attacking secure programs.
Enphasis mine
BTW I think strcat
starts searching for the null terminator
into the dest string before to concatenate the new string, so it is obviously UB, as far as dest
string has automatic storage.
In the proposed code
for (int i=0 ; i<SIZE1 ; i++){
res[i] = a[i];
}
Copy 5
chars of a
and not the null terminator to res
string, so other bytes from 5
to 14
are uninitialized.
Standard also says about safaer implementation strcat-s
K.3.7.2.1 The strcat_s function
Synopsis
#define _ _STDC_WANT_LIB_EXT1_ _ 1 #include <string.h> errno_t strcat_s(char * restrict s1, rsize_t s1max, const char * restrict s2);
Runtime-constraints
2 Let m denote the value s1max - strnlen_s(s1, s1max) upon entry to strcat_s.
We can see that strlen_s
always return them valid size for the dest
buffer. From my point of view this implementation was introduced to avoid the UB of the question.
回答3:
If you leave res
uninitialized then, after the copying a
into res
(in for loop), there's no NUL terminator in res
. So, the behaviour of strcat()
is undefined if the destination string doesn't contain a NUL byte.
Basically strcat()
requires both of its arguments to be strings (i.e. both must contain the terminating NUL byte). Otherwise, it's undefined behaviour. This
is obvious from the description of strcat()
:
§7.23.3.2, strcat() function
The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1.
(emphasis mine).
回答4:
If char res[SIZE3];
is on the stack, it'll have random/undefined stuff in it.
You'll never know whether there'll be a zero byte within res[SIZE3]
, so yes, strcat
ting to that is undefined.
If char res[SIZE3];
is an uninitialized global, it'll be all zeros, which will make it behave as an empty c-string, and strcat
ing to it will be safe (as long as SIZE3 is large enough for what you're appending).
来源:https://stackoverflow.com/questions/38892901/is-it-undefined-behavior-if-the-destination-string-in-strcat-function-is-not-nul