让我们考虑这两行:
char input[1];
gets(input);
假设输入是“测试”。 printf(“%s \ n”,输入)=> “测试”,但如果我使用调试器,我看到输入[0] ='t'没有输入[1] ... 究竟发生了什么?
答案 0 :(得分:10)
那是缓冲区溢出,fyi。为了好玩,请在char untouched[20];
之后添加char input[1];
并打印untouched
。不要使用gets()
,使用fgets()
或其他带边界检查的内容。
调试器没有显示input[1]
,因为没有这样的东西。您的char input[1];
声明分配长度为1的数组,而不是0到1之间的数组。
答案 1 :(得分:7)
gets(s)从stdin读取一行 s指向的缓冲区直到 要么是终止换行符,要么是EOF, 它替换为'\ 0'。没检查 执行缓冲区溢出
http://linux.die.net/man/3/gets
执行gets时,输入被写入s指向的缓冲区。然后它添加一个\ 0。只有't'在输入缓冲区内。其余的,位于堆栈上的连续内存中。 printf打印“test”,因为它可以从s开始读取到第一个\ 0。但是“est \ 0”不在缓冲区之内。
------
| t | input - Debugger only sees this position.
------
| e | Memory you are stepping onto. Trouble if it doesn´t belong to your proc.
| s |
| t |
| \0 |
------
当你调试它时,只输入一个char,所以你可以看到所有。
重要的是要看一下“不检查缓冲区溢出是否已执行”。这意味着如果为输入分配了内存,则获取函数并不在意。它将从您指示的点开始复制所有内容。如果您不小心,那么您的输入可以进入重要信息。在某些最糟糕的情况下,这将是您的函数的返回地址(您使用获取的地方)。 “只是犯”这个错误的人会说“wtf正在进行”。故意这样做的人会将您的返回地址指向特定部分,并执行位于那里的代码。
答案 2 :(得分:2)
你溢出缓冲区,就是这样。你写的是不属于你的记忆并且很幸运。
答案 3 :(得分:2)
此:
char input[1];
只保留一个字符的内存值,但是你输入了五个字符。
调试器知道你只有一个角色,并会告诉你它知道你拥有什么。
正在运行的程序会将字符串泼洒在input
附近的任何内存中,然后崩溃或逃脱它。在你的情况下,你正在逃避它。
答案 4 :(得分:1)
长度为n的char []将最后一个条目存储在位置n-1中。所以,
char input[1];
表示存储在数组输入中的单个char类型数据,位置为0。
(编辑提供一些澄清 - 第一句措辞太糟糕了。)
答案 5 :(得分:0)
声明一个固定大小为“1”的数组。数组中第一个元素的索引始终为“0”。这就是为什么输入[0]保持字符't'。
编辑 - 其余部分存储在缓冲区外的某个位置(BufferOverFlow)。