CodeQL documentation

Type confusion

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 

Click to see the query in the CodeQL repository

Certain casts in C and C++ place no restrictions on the target type. For example, C style casts such as (MyClass*)p allows the programmer to cast any pointer p to an expression of type MyClass*. If the runtime type of p turns out to be a type that’s incompatible with MyClass, this results in undefined behavior.

Recommendation

If possible, use dynamic_cast to safely cast between polymorphic types. If dynamic_cast is not an option, use static_cast to restrict the kinds of conversions that the compiler is allowed to perform. If C++ style casts is not an option, carefully check that all casts are safe.

Example

Consider the following class hierachy where we define a base class Shape and two derived classes Circle and Square that are mutually incompatible:

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(); }; 

The following code demonstrates a type confusion vulnerability where the programmer assumes that the runtime type of p is always a Square. However, if p is a Circle, the cast will result in undefined behavior.

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(); } 

The following code fixes the vulnerability by using dynamic_cast to safely cast between polymorphic types. If the cast fails, dynamic_cast returns a null pointer, which can be checked for and handled appropriately.

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  } } 

References