使用sscanf读取数字时如何导致崩溃?

11

Cppcheck检测到类似于这样的代码可能存在潜在问题:

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

这里说的是:"scanf没有字段宽度限制可能会在处理大量数据时导致崩溃"。这是怎么可能的呢?这是某些sscanf实现中已知的错误吗?我理解数字可能会出现溢出,但程序怎么会崩溃呢?这是cppcheck中的误报吗?

我找到了一个类似的问题:scanf Cppcheck warning,但答案并不能完全令人满意。答案提到了类型安全性,但这在这里不应该是问题。


请尝试使用sscanf_s。与普通的scanf不同,sscanf不具备溢出保护功能。 - guitarflow
2
@guitarflow:问题在于我看不到它可能会溢出的地方。 - Juraj Blaho
2
@guitarflow 或者不用也行。sscanf_s 不具备可移植性,且与其名称和微软所声称的安全性实际上并不一致。 - Konrad Rudolph
http://en.wikipedia.org/wiki/Format_string_attack 也很重要。缓冲区溢出并不是扫描中唯一的漏洞。如果允许用户输入格式字符串,则他们可以使用%x打印任意内存位置,并使用%n编写它们。还有其他内容。 - synthesizerpatel
2
@synthesizerpatel:正如你所看到的,format在这里是一个字符串字面量,所以那不是问题。 - Juraj Blaho
显示剩余4条评论
3个回答

7

我是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进行编译。


1
问题仍然存在。为什么会崩溃?当解析数字的代码可以像这样:for each digit in data: result*=10; result+=digit时,我看不出任何原因导致它崩溃。为什么没有修复呢? - Juraj Blaho
我主要想回答“Cppcheck中是否存在误报?”这个问题。这是一个奇怪的崩溃,所以很容易这么想。我无法回答为什么技术上会崩溃。这是多年来已知的普遍问题。我同意,使用您的代码不可能崩溃,因此数据解析方式显然不是这样的。 - Daniel Marjamäki
是的,我明白了。至少谢谢你给出了部分答案。我给你点赞了。 - Juraj Blaho

4

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

我刚刚测试了一个类似的程序,在ubuntu 10.04崩溃了,但在ubuntu 12.04中工作正常。

正如Daniel Marjamäki所说,他的程序在11.10中崩溃,我相信该错误已经在两个版本之间得到修复。


1

好的,考虑一下这段代码:

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在这方面是完全错误的。


你用了哪些编译器来检查这个? - Mr Lister
只使用g++编译了吗?为什么,你用另一个编译器得到了不同的结果? - WeaselFox
1
还没有,但是我觉得在只测试了一个编译器的情况下得出“CppCheck完全错误”的结论可能有些过早。(抱歉,我现在只能使用VC++2005进行测试。) - Mr Lister
你在编译器中尝试过Daniel Marjamäki发布的示例了吗? - Juraj Blaho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接