问题 如何使用sscanf读取数据崩溃?


Cppcheck在这样的代码中发现了一个潜在的问题:

float a, b, c;
int count = sscanf(data, "%f,%f,%f", &a, &b, &c);

它说:“没有字段宽度限制的scanf会因大量数据而崩溃”。怎么可能?这是某些sscanf实现中的已知错误吗?我知道数字可能会溢出(数字),但程序怎么会崩溃?这在cppcheck中是误报吗?

我发现了类似的问题: scanf Cppcheck警告,但答案并不完全令人满意。答案提到了类型安全,但这不应该是一个问题。


4412
2018-02-15 11:53


起源

请尝试使用sscanf_s。与正常scanf一样,sscanf不是溢出安全的。 - guitarflow
@guitarflow:问题是我看不到溢出的地方。 - Juraj Blaho
@guitarflow或者不要。 sscanf_s 尽管顾名思义并且微软声称,它不是便携式的,也不是真正安全的。 - Konrad Rudolph
en.wikipedia.org/wiki/Format_string_attack 注意也很重要。仅缓冲区溢出并不是扫描中唯一的漏洞。如果允许用户输入格式字符串,则可以使用%x打印任意内存位置,使用%n编写它们。除其他事项外。 - synthesizerpatel
@synthesizerpatel:正如你所看到的,format在这里是一个字符串文字,所以这不是问题。 - Juraj Blaho


答案:


我是Cppcheck开发人员。

是的,这是一个奇怪的崩溃。 “巨大的数据”意味着数百万的数字。

如果你使用--verbose标志,那么cppcheck实际上会编写一个通常在linux计算机上崩溃的示例代码。

以下示例代码在我的Ubuntu 11.10计算机上崩溃并出现分段错误:

#include <stdio.h>

#define HUGE_SIZE 100000000

int main()
{
    int i;
    char *data = new char[HUGE_SIZE];
    for (int i = 0; i < HUGE_SIZE; ++i)
        data[i] = '1';
    data[HUGE_SIZE-1] = 0;
    sscanf(data, "%i", &i);
    delete [] data;
    return 0;
}

对于您的信息,当我在visual studio上尝试这个示例代码时,我不会崩溃。

我使用g ++版本4.6.1进行编译。


7
2018-02-15 14:49



问题仍然存在。为什么会崩溃?我没有看到解析数字的代码可能是这样的原因: for each digit in data: result*=10; result+=digit。怎么可能崩溃?为什么不修复? - Juraj Blaho
我主要想回答“这在Cppcheck是误报吗?”。这是一个奇怪的崩溃所以很容易这么想。我不能回答为什么技术上它会崩溃。多年来,它一直是一个众所周知的问题。我同意,对于你的代码,它不会崩溃,显然不是数据的解析方式。 - Daniel Marjamäki
是的我明白。至少谢谢你的部分答复。我给了你+1。 - Juraj Blaho


分段错误似乎是glibc中的一个错误。

我刚用类似的程序对它进行了测试,该程序在ubuntu 10.04中崩溃, 但适用于ubuntu 12.04。

正如DanielMarjamäki所说,他的程序在11.10崩溃,我相信这个错误 介于两者之间。


4
2018-06-12 14:34





好的,请考虑以下代码:

int main(int argc, char *argv[]) {
    const char* data = "9999999999999999999999999.9999999999999999999999//i put alot more 9's there, this just to get the point through
    float a;
    int count = sscanf(data, "%f", &a);
    printf("%f",a);
}

这个程序的输出是“inf” - 没有崩溃。我在那里放了大量的9。所以我怀疑Cppcheck对此是完全错误的。


1
2018-02-15 12:48



您检查过哪些编译器? - Mr Lister
用g ++编译。为什么,你有另一个编译器得到不同的结果? - WeaselFox
还没有,但我觉得在仅仅1个编译器上测试时,结论“CppCheck是完全错误的”可能有点为时过早。 (我只能用我现在坐的VC ++ 2005进行测试,抱歉。) - Mr Lister
您是否尝试过DanielMarjamäki在您的编译器中发布的示例? - Juraj Blaho