缓冲区溢出时的分段错误

时间:2015-11-24 18:02:18

标签: c return buffer warnings

我无法运行此c代码。当我这样做时,我得到分段错误,并且错误地返回' return 0xdeadbeef;

有人有任何建议吗?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int lame(unsigned int size, unsigned int value){

unsigned int array1[4];
unsigned int array2[6];
array2[5] = value;
memcpy(&array1, &array2, size * sizeof(unsigned int));

return 1;
}

void awesome(){
printf("awwwwwww yeaaahhhhh! All awesome, all the time!\n");
}

main(unsigned int argc, char ** argv){
unsigned int size, value;
size = strtoul(argv[1], 0, 10);
value = strtoul(argv[2], 0, 16);

if(!lame(size, value)){
    awesome();
}
else{
    printf("I am soooo lame :(\n");
}

return 0xdeadbeef;
}

1 个答案:

答案 0 :(得分:2)

我说在你的代码的几乎每一行都有“至少一个bug”,现在我将列出它们。如果我对某一行没有任何评论,那么该行上就没有错误,但您还需要阅读正确的代码格式和样式。

int lame(unsigned int size, unsigned int value){
unsigned int array1[4];
unsigned int array2[6];
array2[5] = value;
memcpy(&array1, &array2, size * sizeof(unsigned int));
return 1;
}

如果memcpy大于4,size行上的未定义行为。由于size来自用户输入,此程序包含缓冲区溢出漏洞,尽管可能很难利用。 (您需要阅读“Smashing the Stack for Fun and Profit。”)

此功能没有外部可见的副作用。除return 1之外,编译器可能并且可能会删除所有代码

应该重构始终返回相同常量值的函数以返回void。在当前文件之外未使用的函数应声明为static

void awesome(){
printf("awwwwwww yeaaahhhhh! All awesome, all the time!\n");
}

printf的使用可以由puts替换。在当前文件之外未使用的函数应声明为static

main(unsigned int argc, char ** argv){

main的第一个参数必须为int,而不是unsigned int。缺少返回类型(必须为int,而不是void);许多编译器会容忍这种情况(将其视为隐式返回int)以便与C89之前的代码向后兼容,但它仍然是错误的。

unsigned int size, value;
size = strtoul(argv[1], 0, 10);
value = strtoul(argv[2], 0, 16);

sizevalue都应为unsigned long,以便与strtoul返回的内容保持一致。

如果命令行参数少于两个,则为未定义的行为。

需要检查对strtoul的两次调用是否失败。这非常重要;阅读EXAMPLES section of the OpenBSD manpage for strtoul以了解如何正确

但是,使用strtoul而不是atoi无法检查失败)或sscanf(在整数上有未定义的行为)的道具溢出)。

if(!lame(size, value)){
    awesome();
}
else{
    printf("I am soooo lame :(\n");
}

编译器可以并且将确定lame始终返回1,并优化对awesome的调用。 (事实上​​,它有权优化所有但上面的printf,因为所有控制流路径都会触发未定义的行为或者它们到达printf,并且没有其他外部可见效果。我很容易掌握的编译器并不那么聪明,但是他们删除if-then-else和lame内的所有代码。)

printf的使用也可以由puts替换。

当你停止称自己为跛足时,你将自动减少23%的跛脚。

return 0xdeadbeef;

main返回的值很有意义。 0表示整个程序的成功,任何其他值意味着某种失败。除非您打算指示失败,否则始终返回0。此外,父流程跨平台只能可靠地接收范围[0,127]中的值; 0xdeadbeef是正确的。

在屏幕截图中,main返回了void,而不是丢失了返回类型;加上带有值的return语句应该导致程序无法编译。但是,您的编译器可能会在main中容忍它。