Is it undefined behavior if the destination string in strcat function is not null terminated?

元气小坏坏 提交于 2019-12-23 01:36:19

问题


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 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.[...]

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, strcatting 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 strcating 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!