设定:
给定这种代码:
char myString[4];
printf("%s\n", myString);
strncpy(myString, "hi", 2);
printf("%s\n", myString);
strncat(myString, "h123", 2);
printf("%s\n", myString);
这将打印:
KU�
hiU�
hiU�h1
我的期望:
在我看来,myString是指向内存中已分配位置的指针,如下所示:
MEMORY: [random][random][random][\0][random][random][random]....
PRINTED: [random][random][random][\0]
它在字符串开头之后的第四个位置添加一个指向内存的空指针
在strncpy之后:
MEMORY: [h][i][random][\0][random][random][random]...
PRINTED: [h][i][random][\0]
它将前2个字符更改为hi,并且不添加\ 0
在strncat之后:
MEMORY: [h][i][random][h][1][2][3][\0]...
PRINTED: [h][i][random][h][1][2][3][\0]
它在字符串开头之后查找\ 0,然后删除\ 0并添加自己的字符串,并在结尾添加\ 0。
我所期望的没有发生。
题:
那里正在打印什么?
如果我期望的那一部分是错误的理解?
注意:
现在,我了解到这种未定义的行为,应该避免,但是我是从尝试理解可以在给定代码上使用的所有可能利用的角度出发的。
我不是在寻找正确的编码实践。我正在寻找对到底出了什么问题的理解。
编辑1
我确实知道文档说它的不确定行为,并且从开发人员的角度来看,必须避免鼻恶魔的可能性。
但是从开发者的角度来看,这里正在发生某些事情,这不仅可能是错误,而且还可能是安全漏洞,可以更深入地理解它,从而可以形成一致的漏洞。我希望对此加深了解。的
最佳答案
在我看来,myString是指向内存中已分配位置的指针,如下所示:
MEMORY: [random][random][random][\0][random][random][random]....
也许在您看来,实际上,它看起来像这样:
MEMORY: [random][random][random][random][random][random][random]....
实际上,正如评论所言,字符不是随机的而是不确定的。它们很可能是先前已占用但仍不知道的堆栈帧的残余。
当您在堆栈上分配一个char数组时,没有nul字节被放入。它只是将堆栈指针加4,仅此而已。
编辑
抱歉,我没有读完整个问题就跳了进来。
strncpy(myString, "hi", 2);
上面的行先复制一个h,然后复制一个i,然后停止,因为它已经复制了两个字符。如果明智的话,它只会复制h然后是
\0
,但不是。strncat
是一个奇怪的函数,应该将其分配给火热的地狱。它一直到第一个字符串的末尾,然后从第二个字符串和一个终止的\0
加起来最多n个字符。 n与要复制到的缓冲区大小以及溢出缓冲区的大小无关。strncat(myString, "h123", 2);
不能保证您的第一个字符串在任何地方都有一个
\0
(已经讨论过),因此它将把h和1复制到不确定的内存位置。