类型混淆¶
ID: cpp/type-confusion
Kind: path-problem
Security severity: 9.3
Severity: warning
Precision: medium
Tags:
- security
- external/cwe/cwe-843
Query suites:
- cpp-security-extended.qls
- cpp-security-and-quality.qls
C 和 C++ 中的某些强制转换对目标类型没有限制。例如,C 样式的强制转换(如 (MyClass*)p
)允许程序员将任何指针 p
强制转换为类型为 MyClass*
的表达式。如果 p
的运行时类型是与 MyClass
不兼容的类型,则会导致未定义的行为。
建议¶
如果可能,请使用 dynamic_cast
在多态类型之间进行安全地强制转换。如果无法使用 dynamic_cast
,请使用 static_cast
来限制编译器允许执行的转换类型。如果无法使用 C++ 样式的强制转换,请仔细检查所有强制转换是否安全。
示例¶
考虑以下类层次结构,我们定义了一个基类 Shape
和两个派生类 Circle
和 Square
,它们互不兼容
struct Shape {
virtual ~Shape();
virtual void draw() = 0;
};
struct Circle : public Shape {
Circle();
void draw() override {
/* ... */
}
int getRadius();
};
struct Square : public Shape {
Square();
void draw() override {
/* ... */
}
int getLength();
};
以下代码演示了一个类型混淆漏洞,其中程序员假设 p
的运行时类型始终为 Square
。但是,如果 p
是 Circle
,则强制转换将导致未定义的行为。
void allocate_and_draw_bad() {
Shape* shape = new Circle;
// ...
// BAD: Assumes that shape is always a Square
Square* square = static_cast<Square*>(shape);
int length = square->getLength();
}
以下代码通过使用 dynamic_cast
在多态类型之间进行安全地强制转换来修复此漏洞。如果强制转换失败,则 dynamic_cast
将返回一个空指针,可以对其进行检查并进行适当的处理。
void allocate_and_draw_good() {
Shape* shape = new Circle;
// ...
// GOOD: Dynamically checks if shape is a Square
Square* square = dynamic_cast<Square*>(shape);
if(square) {
int length = square->getLength();
} else {
// handle error
}
}