☰
  • 首页
  • 规则分类
  • 项目介绍
search
•••

C 格式化占位符与其对应参数的类型应一致

10.6.7 ID_inconsistentFormatArgType
目录 › next › previous

C 格式化占位符与其对应参数的类型应一致,否则会导致标准未定义的行为。

示例:

size_t n;
ptrdiff_t d;
....
printf("%u", n);    // Non-compliant
printf("%d", d);    // Non-compliant
printf("%lu", n);   // Non-compliant
printf("%lld", d);  // Non-compliant

size_t、ptrdiff_t 等类型是由实现定义的,标准没有规定其是否一定对应 unsigned、long 或 long long 等类型,而 %u、%d、%lu、%lld 只对应 unsigned、int、unsigned long、long long 等类型,所以示例代码都是不合理的。

应使 n 对应 %zu,d 对应 %td:

printf("%zu", n);   // Compliant
printf("%td", d);   // Compliant

对于 stdint.h 中定义的类型,应使用 inttypes.h 中定义的占位符:

int32_t i;
uint64_t u;
....
printf("%d", i);    // Unportable
printf("%lu", u);   // Unportable

printf("%" PRId32, i);   // OK
printf("%" PRIu64, u);   // OK

int32_t、uint64_t 并不一定对应 int、unsigned long,不应将 %d、%lu 等占位符在代码中写死,PRId32 和 PRIu64 是 inttypes.h 中定义的宏,可解决移植相关的问题。

又如:

void foo(const string& msg) {
    printf("%s\n", msg);        // Non-compliant
}

例中 %s 要求对应 char* 型指针,但 msg 是 string 型对象,造成栈读取错误,应改为:

void foo(const string& msg) {
    printf("%s\n", msg.c_str());   // Compliant
}

由于可变参数列表自身的局限,很难在编译时发现这种问题,有些编译器会检查 printf、sprintf 等标准函数,但无法检查自定义函数,建议在 C++ 代码中禁用可变参数列表和 C 风格的格式化函数。

相关

ID_nonPODVariadicArgument ID_inconsistentFormatArgNum ID_forbidCStringFormat

依据

ISO/IEC 9899:1999 7.19.6.1(9)-undefined ISO/IEC 9899:2011 7.21.6.1(9)-undefined

参考

CWE-686 SEI CERT FIO47-C
Copyright©2024 360 Security Technology Inc., Licensed under the Apache-2.0 license.