4

我知道普通代码有可能溢出:

字符字符串[9];

scanf("%s", 字符串)。

但是是否有可能溢出 scanf("%8s", string)?8只是一个例子。

我知道“%8s”就像一个分隔符,但我也注意到当我输入超过 8 个字符的字符串时,程序将因以下原因终止:

* 检测到堆栈粉碎 * : ./a.out 终止

======= 回溯:=========

...

显然,默认情况下,有一个标志可以检测 GCC 打开的堆栈粉碎。既然这是一个堆栈粉碎,那么我的猜测是仍然有可能溢出并执行任意代码。

与破坏 scanf("%s") 调用者的正常溢出相反,如果 scanf("%8s") 可以溢出,它将在 scanf 函数内溢出,以便当 scanf 尝试返回时,获得控制权。

但是 scanf 是一个需要模式切换(从用户模式切换到内核模式)的系统调用,并且在内部它会调用诸如读取到标准输入等的东西。所以不确定我们是否可以在内核模式下溢出或其他东西..

欢迎评论!!

更新>>

char string[9] 假设在上面的例子中。以下实际代码中的 char string[8]。

问题实际上是关于安全 scanf("%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;
       ...
   } 

}

}

笔记:

  1. foo 被其他人调用。
  2. 尽管字符串在带有“%8s”的实际代码中是 8 个字节,但我认为这不会导致崩溃。
4

4 回答 4

9

http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html

每个指令由以下之一组成...一个可选的非零十进制整数,指定最大字段宽度。

s
匹配不是空白字符的字节序列。应用程序应确保相应的参数是指向 char、signed char 或 unsigned char 数组的初始字节的指针,该数组大到足以接受序列和终止的空字符代码,应自动添加。

所以它不会溢出一个 9 字节的字符串缓冲区。

于 2009-11-24T05:21:21.600 回答
3

如果您希望输入可靠,则永远不要使用scanf(或就此而言)。fscanf

您应该使用fgets(或类似的“防止缓冲区溢出”变体)然后使用sscanf它。

scanfand的主要问题fscanf是如果该行不是预期的格式(即,如果scanf失败),您的文件指针可能最终处于不确定的位置。使用该fgets/sscanf方法,可以更轻松地确保您在行边界上,而无需使用ftellfseek移动文件。

关于您关于缓冲区是否会溢出的具体查询,C 标准有这样的说法:

...相应的参数应该是一个指向一个字符数组的初始元素的指针,该数组的大小足以接受序列和一个终止的空字符,它将自动添加。

因此,对于一种"%8s"格式,您需要一个 9 字符数组。

我怀疑您的代码中还有其他问题。使用测试程序:

#include <stdio.h>
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] [ ]
于 2009-11-24T05:19:58.310 回答
1

如果分配的字符串少于 8 个包,它肯定会覆盖缓冲区,而且 scanf 也不会附加空终止符。但是,只要您在字符串中有足够的空间来存储您的值,就不会被过度覆盖。

于 2009-11-24T05:13:15.610 回答
1

正如 ysth 所指出的,该数组应该能够包含字符串终止的空字符,因此使用 8 字节数组(特别是如果它是在堆栈上分配的,因为它在您的代码中)很可能会弄乱它向上。

于 2009-11-24T06:14:09.340 回答