扫描溢出(“%8s”,字符串)?
我知道溢出普通代码是可能的:
char string [9];
scanf(“%s”,string)。
但是有可能溢出scanf(“%8s”,字符串)? 图8只是一个例子。
我知道“%8s”就像分隔符一样,但我也注意到当我输入长度超过8个字符的字符串时,程序将因以下原因而终止:
*堆栈粉碎检测到* :./a.out终止
======= Backtrace:=========
…
显然,有一个标志可以检测GCC默认打开的堆栈粉碎。 由于这是一个堆栈粉碎,我的猜测是它仍然可以溢出并执行任意代码。
与正常溢出相反,会破坏scanf(“%s”)的调用者,如果scanf(“%8s”)可能溢出,它将在scanf函数内溢出,以便当scanf尝试返回时,获得控制权。
但是scanf是一个系统调用,它需要模式切换(从用户模式切换到内核模式),并且在内部它会调用诸如read之类的东西到stdin等。所以不确定我们是否可以在内核模式或其他东西中溢出..
欢迎评论!!
更新>>
在上面的例子中假设了char字符串[9]。 char字符串[8]在以下实际代码中。
问题实际上是关于安全扫描(“%8s”)和GCC流产之间由于堆栈粉碎而看似矛盾的故事。
简化代码:
void foo(pass some pointer) { char input[8]; int input_number = 0; while (1) { // looping console printf some info; scanf("%8s", input); input_number = atoi(input); if ((strlen(input) == 1) && (strncmp(input, "q", 1) == 0)) { input_number = -1; } switch (input_number) { case -1: to quit the console if input = 'q'; default: to print info that pointer refers to; ... } } }
注意:
- foo被别人叫。
- 虽然字符串是实际代码中的8个字节,带有“%8s”,但我认为这不会导致粉碎。
见http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html :
每个指令由以下之一组成…一个可选的非零十进制整数,指定最大字段宽度。
小号
匹配不是空格字符的字节序列。 应用程序应确保相应的参数是指向char,signed char或unsigned char数组的初始字节的指针,其大小足以接受序列和终止空字符代码,这些代码应自动添加。
所以它不会溢出9字节的字符串缓冲区。
如果您希望输入稳健,请不要使用scanf
(或fscanf
)。
您应该使用fgets
(或类似的“受缓冲区溢出保护”变体)然后使用sscanf
。
scanf
和fscanf
的主要问题是,如果行不是预期的格式(即,如果scanf
失败),则文件指针可能会以不确定的位置结束。 使用fgets/sscanf
方法,可以更加轻松地保证您处于行边界,而无需使用ftell
和fseek
来移动文件。
关于缓冲区是否会溢出的具体查询,C标准有这样的说法:
…相应的参数应该是一个指向大小足以接受序列的字符数组的初始元素的指针和一个将自动添加的终止空字符。
因此,对于"%8s"
格式,您需要一个9个字符的数组。
我怀疑你的代码中还有其他一些问题。 有了测试程序:
#include int main(int argc, char* argv[]) { char x1; char a[9]; char x2; x1 = x2 = ' '; scanf ("%s",a); printf ("[%c] [%s] [%c]\n",x1,a,x2); return 0; }
我明白了:
pax> ./qq.exe dfjdhadgha...lghjdfgjhd [s] [dfjdhadgha...lghjdfgjhd] [ ] 6 [main] qq 4744 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack) Segmentation fault (core dumped)
当我改变同一个程序以使用"%8s"
,我得到(对于完全相同的输入):
pax> ./qq.exe dfjdhadgha...lghjdfgjhd [ ] [dfjdhadg] [ ]
如果为少于8个章程分配字符串,它肯定会覆盖缓冲区,scanf也不会附加空终止符。 但是只要你的字符串中有足够的空间来代替你的价值,你就不应该过分重视。
正如ysth指出的那样,数组应该能够包含字符串和终止空字符,所以使用8字节数组(特别是如果它在堆栈中分配,就像在代码中一样)很可能会弄乱它起来。