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