Eclipse C 字符串不溢出
Eclipse C string does not overflow
我正在为 C/C++ 开发人员使用 Eclipse IDE,同时我学习 C。理论上,当我输入大于我分配的字符串的大小时,溢出应该以某种方式发生.但这一切都很好,我没有看到想要的麻烦。
int main()
{
char nameArr[15];
printf("Type name: ");
scanf("%s",nameArr);
printf("You are %s.\n",nameArr);
return(0);
}
我想特意看看溢出的情况,但是我看不到。例如,当 运行 时,如果我键入 Wolfeschlegelsteinhausenbergerdorff,它会在 Eclipse 中正确输出而没有任何与溢出相关的消息。我不知道它是 C 的特性还是 Eclipse 的特性。有谁知道为什么超大号没问题?
正如@retiredninja 在评论中提到的那样,缓冲区溢出会导致未定义的行为,因此您不能期望任何事情发生或不发生。
话虽如此,要观察一些简单的缓冲区溢出,你可以试试这个:
#include <stdio.h>
int main()
{
char overflow[16];
char nameArr[16];
overflow[15] = '[=10=]';
nameArr[15] = '[=10=]';
printf("Type name: ");
scanf("%s" ,nameArr);
printf("You are %s.\n", nameArr);
printf("overflow: %s\n", overflow);
return(0);
}
当我用
编译它时
gcc -Wall -W main.c -o main -fno-stack-protector -O0
和运行吧,我明白了
$ ./main
Type name: 123456789abcdefghijklmnopqrstuvwxyz
You are 123456789abcdefghijklmnopqrstuvwxyz.
overflow: hijklmnopqrstuvwxyz
这表明额外的文本被写入了与预期变量相邻的内存中。这里的顺序很重要:这些变量存在于堆栈中,堆栈通过内存向下增长,因此内存 'after' 变量属于在它之前声明的变量。
请注意,我的回答中的所有内容都是 implementation-dependent,因此不能指望所有编译器、操作系统等都会出现这种情况。尤其如此,因为我们正在谈论未定义的行为。
这个例子很好地说明了为什么使用您可以随意使用的工具来捕获常见的编程错误很重要。像这样的数组溢出可能多年未被发现,直到有人将其用作漏洞利用的基础。很容易犯这种错误——它们通常不像 OP 中的错误那么明显——而且它们在测试时不一定会导致失败。
现代 C 编译器提供保护,防止数组从堆栈末尾注销。他们不能使代码 工作 ,但他们可以发出失败信号,以便可以跟进错误。例如,如果我使用 -fstack-protector
使用 gcc
构建 OP 的代码,那么即使是小的超限也会立即导致失败:
Type name: 12345678987654321
You are 12345678987654321.
*** stack smashing detected ***: <unknown> terminated
与调试器结合使用,可以非常快速地检测到问题代码。
如果您的编译器不提供此类检查,请获取更好的编译器;)
我正在为 C/C++ 开发人员使用 Eclipse IDE,同时我学习 C。理论上,当我输入大于我分配的字符串的大小时,溢出应该以某种方式发生.但这一切都很好,我没有看到想要的麻烦。
int main()
{
char nameArr[15];
printf("Type name: ");
scanf("%s",nameArr);
printf("You are %s.\n",nameArr);
return(0);
}
我想特意看看溢出的情况,但是我看不到。例如,当 运行 时,如果我键入 Wolfeschlegelsteinhausenbergerdorff,它会在 Eclipse 中正确输出而没有任何与溢出相关的消息。我不知道它是 C 的特性还是 Eclipse 的特性。有谁知道为什么超大号没问题?
正如@retiredninja 在评论中提到的那样,缓冲区溢出会导致未定义的行为,因此您不能期望任何事情发生或不发生。
话虽如此,要观察一些简单的缓冲区溢出,你可以试试这个:
#include <stdio.h>
int main()
{
char overflow[16];
char nameArr[16];
overflow[15] = '[=10=]';
nameArr[15] = '[=10=]';
printf("Type name: ");
scanf("%s" ,nameArr);
printf("You are %s.\n", nameArr);
printf("overflow: %s\n", overflow);
return(0);
}
当我用
编译它时gcc -Wall -W main.c -o main -fno-stack-protector -O0
和运行吧,我明白了
$ ./main
Type name: 123456789abcdefghijklmnopqrstuvwxyz
You are 123456789abcdefghijklmnopqrstuvwxyz.
overflow: hijklmnopqrstuvwxyz
这表明额外的文本被写入了与预期变量相邻的内存中。这里的顺序很重要:这些变量存在于堆栈中,堆栈通过内存向下增长,因此内存 'after' 变量属于在它之前声明的变量。
请注意,我的回答中的所有内容都是 implementation-dependent,因此不能指望所有编译器、操作系统等都会出现这种情况。尤其如此,因为我们正在谈论未定义的行为。
这个例子很好地说明了为什么使用您可以随意使用的工具来捕获常见的编程错误很重要。像这样的数组溢出可能多年未被发现,直到有人将其用作漏洞利用的基础。很容易犯这种错误——它们通常不像 OP 中的错误那么明显——而且它们在测试时不一定会导致失败。
现代 C 编译器提供保护,防止数组从堆栈末尾注销。他们不能使代码 工作 ,但他们可以发出失败信号,以便可以跟进错误。例如,如果我使用 -fstack-protector
使用 gcc
构建 OP 的代码,那么即使是小的超限也会立即导致失败:
Type name: 12345678987654321
You are 12345678987654321.
*** stack smashing detected ***: <unknown> terminated
与调试器结合使用,可以非常快速地检测到问题代码。
如果您的编译器不提供此类检查,请获取更好的编译器;)