何时量化Csscanf函数中被忽略的模式匹配
When to quantify ignored pattern match in the C sscanf function
Cppcheck 1.67在我的源代码中的这一行提出了一个可移植性问题:
sscanf(s, "%d%*[,;.]%d", &f, &a);
这是我从中得到的信息:
在某些版本的libc上,没有字段宽度限制的scanf可能会因大量输入数据而崩溃。
格式化字符串的初衷是接受两个整数之间的三个可能的限制器字符中的一个,今天,由于Cppcheck[1],我看到%*[,;.]
接受偶数个限制器字符字符串。然而,我怀疑我的格式字符串可能会导致崩溃,因为无限部分被忽略了。
缓冲区溢出可能存在问题吗。。。也许是在幕后
[1]如何在远视和失明之间迷失方向:
我试图通过%1*[,;.]
(在一些API文档之后)修复它,但Cppcheck坚持这个问题,所以我也尝试了%*1[,;.]
,并取得了同样的"成功"。看来我现在必须压抑它。。。
祝贺您在Cppcheck 1.67(当前版本)中发现错误。
基本上有三种解决方法:
- 忽略假阳性即可
-
修改您的格式(指定该字段,可能是因为您只想匹配一个字符)。
char tmp; if(3 != sscanf(s, "%d %c%d", &f, &tmp, &a) || tmp!=',' && tmp!=';' && tmp!= '.') goto error;
-
直接抑制警告(最好是在线抑制):
//cppcheck-suppress invalidscanf_libc if(2 != sscanf(s, "%d%1*[,;.]%d", &f, &a)) goto error;
不要忘记将错误报告为"缺陷/假阳性",这样您就可以尽快退出并忘记该解决方法。
何时量化Csscanf函数中被忽略的模式匹配?
也许总是量化是个好主意(见下文),但过度量化也可能会分散你的注意力。在上面的情况下,必须跳过单个分隔符char,量化肯定是有用的。
缓冲区溢出可能有问题吗。。。也许是在幕后?
您的代码不会导致崩溃。至于处理"幕后"问题,我尝试了大的输入字符串。在我测试的C库中,没有内部缓冲区溢出。我尝试了Borland C++5.6.4附带的C库,发现我无法在大量输入(超过4亿个字符)的情况下触发缓冲区溢出。
令人惊讶的是,Cppcheck并没有完全错-存在可移植性问题,但有一个不同的问题:
#include <stdio.h>
#include <assert.h>
#include <sstream>
int traced_sscanf_set(const int count, const bool limited)
{
const char sep = '.';
printf("n");
std::stringstream ss;
ss << "123" << std::string(count, sep) << "456";
std::string s = ss.str();
printf("string of size %d with %d '%c's in itn", s.size(), count, sep);
std::stringstream fs;
fs << "%d%";
if (limited) {
fs << count;
}
fs << "*["<< sep << "]%d";
std::string fmt = fs.str();
printf("fmt: "%s"n", fmt.c_str());
int a = 0;
int b = 0;
const sscanfResult = sscanf(s.c_str(), fmt.c_str(), &a, &b);
printf("sscanfResult=%d, a=%d, b=%dn", sscanfResult, a, b);
return sscanfResult;
}
void test_sscanf()
{
assert(traced_sscanf_set(0x7fff, true)==2);
assert(traced_sscanf_set(0x7fff, false)==2);
assert(traced_sscanf_set(0x8000, true)==2);
assert(traced_sscanf_set(0x8000, false)==1);
}
我检查的库在内部将消耗(和跳过)的输入限制为32767(215-1)个字符,如果在format参数中没有明确指定的限制。
对于那些感兴趣的人,这里是跟踪输出:
string of size 32773 with 32767 '.'s in it
fmt: "%d%32767*[.]%d"
sscanfResult=2, a=123, b=456
string of size 32773 with 32767 '.'s in it
fmt: "%d%*[.]%d"
sscanfResult=2, a=123, b=456
string of size 32774 with 32768 '.'s in it
fmt: "%d%32768*[.]%d"
sscanfResult=2, a=123, b=456
string of size 32774 with 32768 '.'s in it
fmt: "%d%*[.]%d"
sscanfResult=1, a=123, b=0
- 模式匹配文本并提取C++中的数据
- 如何在CLIPS中优化不同模板事实之间的模式匹配
- Flex Lexer 模式匹配句子分隔符/标点符号作为 URL 路径部分
- C++中的模式匹配
- 模式匹配函数的时间测量无法正常工作
- C++向量的模式匹配
- 从.cpp文件中提取与模式匹配的"if"块
- 在某些情况下,通配符模式匹配失败
- 如何使用C++模板魔术来对类型进行模式匹配
- 使用 std::regex_search 获取与模式匹配的所有文件和文件夹
- 在 c++-17 中特化的模式匹配中 lambda 的拆分函数签名
- C++;仅当用户输入与预设模式匹配时才接受用户输入
- 下一个最大的整数,有一些中间位与模式匹配?
- 模板模式匹配
- 用于多个级联字符串的同步模式匹配算法
- 使用C++功能在系统路径中进行模式匹配
- 使用[msys]bash删除所有名称与模式匹配的文件,而不考虑文件名字母大小写
- DNA模式匹配中最快的算法是什么
- 使用后缀数组和 LCP(-LR) 实现字符串模式匹配
- 何时量化Csscanf函数中被忽略的模式匹配