我收到了以下代码:
char *func(char * a)
{
char b[1000];
strcpy(b,a);
return b;
}
(我知道代码很糟糕,因为我返回数组的地址,当我退出函数时会删除。)我的问题是,如果我输入" a&#将删除/覆盖什么34;,一组2000个字符," b"只有1000个字符数组。我在某处读到了这个问题,他们说通过这段代码我可以知道什么会覆盖。
答案 0 :(得分:1)
似乎你不熟悉堆栈的想法。当程序控制进入函数时,指向堆栈的指针被赋予程序控制。并且所有局部变量都在此堆栈上分配。当程序从函数返回时,堆栈指针被改变为它的原始值。因此b在堆栈上并为其分配1000个字节。当程序从func返回时,实际上没有任何东西会被删除或覆盖,直到其他一些函数使用该堆栈区域。您可以尝试访问' b'在你从功能出来后它必须工作。但是在调用' func'之后你打电话给另一个功能' func1'有一些局部变量然后更新这些变量将覆盖b指向的内容
答案 1 :(得分:0)
什么将被删除/覆盖,如果我输入“a”,一个2000个字符的数组,而“b”只有1000个字符数组。
行为未定义。从标准的角度来看,没有任何保证。有些内存可能被覆盖,或者可能没有。在实践中,可能会覆盖一些内存。
纠正我,如果我错了,这个溢出,将重写指针的值。正确?
可以。它可能不会。行为未定义。
将会发生什么取决于编译器,编译器的版本,cpu体系结构,编译选项,如何定义程序的其余部分以及可能的其他因素。
在典型的实现中,返回值适合寄存器并且是编译时常量,因此实际上它不可能存储在堆栈中,在这种情况下它不会受溢出的影响。还有更危险的潜在副作用,例如函数在完全不同的地方返回而不是从它被调用的地方返回。
答案 2 :(得分:0)
如果你传递的a
中的C字符串大于你为b
分配的空间(1000字节),那么它会愉快地写出b
的结尾并向下通过b
下面的堆栈中的任何内容。 C字符串没有定义的长度。 strcpy(b,a)
将继续将字节复制到b
,直到在\0
内找到a
为止。在函数func
的堆栈中,编译器将为b
保留1000个字节,然后将返回地址保存到任何名为func
的地址。如果a
覆盖b
,您将覆盖返回地址,当func
返回时,您将跳转到某个随机地址并产生可怕的结果。每个编译器都可以自由地将函数的返回地址放在任何地方。也许它将返回地址放在堆栈的顶部。但即使在那种情况下,你也会写下你不应该写的东西。如果你很幸运,你将获得访问冲突。
为防止出现这种情况,您可以使用strncpy(b,a,sizeof(b)-1)
并在\0
末尾添加b
。最好检查strlen(a)
并在strlen(a) > sizeof(b)-1
。
这正是黑客用来打破Windows安全限制的“缓冲区溢出”技术。您调用一个需要C字符串但不检查传入的C字符串长度的Windows函数。传入的字符串会猜测输入缓冲区的长度,最终会正确猜测并覆盖返回地址指向传入的字符串的函数。输入字符串的其余部分包含机器代码指令,然后在Windows函数的安全权限下运行。然后它可以做任何想做的事。
微软很久以前就关闭了这个安全漏洞,但是检查你接受的C字符串长度作为输入参数仍然是一个很好的教训。