CERT.VA_START.TYPE
传递给 va_start() 的参数类型在实现间必须有明确定义的行为。具体而言,该参数不得为
- 引用
- 数组
- 带不常用构造函数或析构函数的类
- 在作为参数传递给无原型函数或作为尾随参数传递给可变参数函数时,经过默认提升的某个类型
CERT.VA_START.TYPE 检查器会标记将不支持的对象类型作为第二个参数传递给 va_start() 的情况。
漏洞与风险
将不支持的类型作为第二个参数传递给 va_start() 可能会导致未定义的行为,从而造成数据完整性违规。
缓解与预防
确保传递给 va_start() 的第二个参数是支持的类型。
漏洞代码示例 #1
复制
#include <cstdarg>
extern "C" void f(float a, ...){
va_list list;
va_start(list, a);
// ...
va_end(list);
}
在此符合要求的示例中,Klocwork 在第 5 行报告了 CERT.VA_START.TYPE 缺陷,因为将错误的类型作为第二个参数传递给 va_start()。这是因为默认参数提升后,float 类型会转换为 double,这可能会导致未定义的行为。
修正代码示例
复制
#include <cstdarg>
extern "C" void f(double a, ...){
va_list list;
va_start(list, a);
// ...
va_end(list);
}
漏洞代码示例 #2
复制
#include <cstdarg>
#include <iostream>
extern "C" void f(int &a, ...){
va_list list;
va_start(list, a);
if (a) {
std::cout << a << ", " << va_arg(list, int);
a = 100; // Assign something to a for the caller
}
va_end(list);
}
在此符合要求的示例中,Klocwork 在第 6 行报告了 CERT.VA_START.TYPE 缺陷,因为将错误的引用类型作为第二个参数传递给 va_start(),这可能会导致未定义的行为。
修正代码示例 #2
复制
#include <cstdarg>
#include <iostream>
extern "C" void f(int *a, ...){
va_list list;
va_start(list, a);
if (a && *a) {
std::cout << a << ", " << va_arg(list, int);
*a = 100; // Assign something to *a for the caller
}
va_end(list);
}
以上代码符合要求,因为它将正确类型 double 作为第二个参数传递给 va_start()。
漏洞代码示例 3
复制
#include <cstdarg>
#include <iostream>
#include <string>
extern "C" void f(std::string s, ...){
va_list list;
va_start(list, s);
std::cout << s << ", " << va_arg(list, int);
va_end(list
}
在此符合要求的示例中,Klocwork 在第 7 行报告了 CERT.VA_START.TYPE 缺陷,因为将不常用的复制构造函数作为第二个参数传递给 va_start(),这可能会导致未定义的行为。
修正代码示例 3
复制
#include <cstdarg>
#include <iostream>
extern "C" void f(const char *s, ...){
va_list list;
va_start(list, s);
std::cout << (s ? s : "") << ", " << va_arg(list, int);
va_end(list);
}
以上代码符合要求,因为它传递的是 const char*,而非 std::string,前者具有定义明确的实现。