mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
CPP: Handle cases where the deallocator function is determined dynamically.
This commit is contained in:
@@ -55,6 +55,7 @@ private newtype TOpcode =
|
||||
TVariableAddress() or
|
||||
TFieldAddress() or
|
||||
TFunctionAddress() or
|
||||
TVirtualDeleteFunctionAddress() or
|
||||
TElementsAddress() or
|
||||
TConstant() or
|
||||
TStringConstant() or
|
||||
@@ -887,6 +888,15 @@ module Opcode {
|
||||
final override string toString() { result = "FunctionAddress" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Opcode` for a `VirtualDeleteFunctionAddress`.
|
||||
*
|
||||
* See the `VirtualDeleteFunctionAddressInstruction` documentation for more details.
|
||||
*/
|
||||
class VirtualDeleteFunctionAddress extends Opcode, TVirtualDeleteFunctionAddress {
|
||||
final override string toString() { result = "VirtualDeleteFunctionAddress" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Opcode` for a `ConstantInstruction`.
|
||||
*
|
||||
|
||||
@@ -576,6 +576,22 @@ class FunctionAddressInstruction extends FunctionInstruction {
|
||||
FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An instruction that returns the address of a "virtual" delete function.
|
||||
*
|
||||
* This function, which does not actually exist in the source code, is used to
|
||||
* delete objects of a class with a virtual destructor. In that case the deacllocation
|
||||
* function is selected at runtime based on the dynamic type of the object. So this
|
||||
* function dynamically dispatches to the correct deallocation function.
|
||||
* It also should pass in the required extra arguments to the deallocation function
|
||||
* which may differ dynamically depending on the type of the object.
|
||||
*/
|
||||
class VirtualDeleteFunctionAddressInstruction extends Instruction {
|
||||
|
||||
VirtualDeleteFunctionAddressInstruction() { this.getOpcode() instanceof Opcode::VirtualDeleteFunctionAddress }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a parameter of the enclosing function with the value of the
|
||||
* corresponding argument passed by the caller.
|
||||
|
||||
@@ -576,6 +576,22 @@ class FunctionAddressInstruction extends FunctionInstruction {
|
||||
FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An instruction that returns the address of a "virtual" delete function.
|
||||
*
|
||||
* This function, which does not actually exist in the source code, is used to
|
||||
* delete objects of a class with a virtual destructor. In that case the deacllocation
|
||||
* function is selected at runtime based on the dynamic type of the object. So this
|
||||
* function dynamically dispatches to the correct deallocation function.
|
||||
* It also should pass in the required extra arguments to the deallocation function
|
||||
* which may differ dynamically depending on the type of the object.
|
||||
*/
|
||||
class VirtualDeleteFunctionAddressInstruction extends Instruction {
|
||||
|
||||
VirtualDeleteFunctionAddressInstruction() { this.getOpcode() instanceof Opcode::VirtualDeleteFunctionAddress }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a parameter of the enclosing function with the value of the
|
||||
* corresponding argument passed by the caller.
|
||||
|
||||
@@ -120,9 +120,9 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Call` or `NewOrNewArrayExpr`.
|
||||
* A `Call` or `NewOrNewArrayExpr` or `DeleteOrDeleteArrayExpr`.
|
||||
*
|
||||
* Both kinds of expression invoke a function as part of their evaluation. This class provides a
|
||||
* All kinds of expression invoke a function as part of their evaluation. This class provides a
|
||||
* way to treat both kinds of function similarly, and to get the invoked `Function`.
|
||||
*/
|
||||
class CallOrAllocationExpr extends Expr {
|
||||
|
||||
@@ -2021,13 +2021,37 @@ TranslatedAllocatorCall getTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
|
||||
* The IR translation of a call to `operator delete` as part of a `delete` or `delete[]`
|
||||
* expression.
|
||||
*/
|
||||
class TranslatedDeallocatorCall extends TTranslatedDeallocatorCall, TranslatedDirectCall {
|
||||
class TranslatedDeallocatorCall extends TTranslatedDeallocatorCall, TranslatedCall {
|
||||
override DeleteOrDeleteArrayExpr expr;
|
||||
|
||||
TranslatedDeallocatorCall() { this = TTranslatedDeallocatorCall(expr) }
|
||||
|
||||
final override string toString() { result = "Deallocator call for " + expr.toString() }
|
||||
|
||||
final override Instruction getFirstCallTargetInstruction() {
|
||||
result = this.getInstruction(CallTargetTag())
|
||||
}
|
||||
|
||||
final override Instruction getCallTargetResult() { result = this.getInstruction(CallTargetTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedCall.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = CallTargetTag() and
|
||||
resultType = getFunctionGLValueType() and
|
||||
if exists(expr.getDeallocator())
|
||||
then opcode instanceof Opcode::FunctionAddress
|
||||
else opcode instanceof Opcode::VirtualDeleteFunctionAddress
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
result = TranslatedCall.super.getInstructionSuccessor(tag, kind)
|
||||
or
|
||||
tag = CallTargetTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = this.getFirstArgumentOrCallInstruction()
|
||||
}
|
||||
|
||||
final override predicate producesExprResult() { none() }
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
|
||||
@@ -576,6 +576,22 @@ class FunctionAddressInstruction extends FunctionInstruction {
|
||||
FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An instruction that returns the address of a "virtual" delete function.
|
||||
*
|
||||
* This function, which does not actually exist in the source code, is used to
|
||||
* delete objects of a class with a virtual destructor. In that case the deacllocation
|
||||
* function is selected at runtime based on the dynamic type of the object. So this
|
||||
* function dynamically dispatches to the correct deallocation function.
|
||||
* It also should pass in the required extra arguments to the deallocation function
|
||||
* which may differ dynamically depending on the type of the object.
|
||||
*/
|
||||
class VirtualDeleteFunctionAddressInstruction extends Instruction {
|
||||
|
||||
VirtualDeleteFunctionAddressInstruction() { this.getOpcode() instanceof Opcode::VirtualDeleteFunctionAddress }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a parameter of the enclosing function with the value of the
|
||||
* corresponding argument passed by the caller.
|
||||
|
||||
@@ -2030,4 +2030,40 @@ unsigned int CommaTest(unsigned int x) {
|
||||
(CommaTestHelper(x), 10);
|
||||
}
|
||||
|
||||
void NewDeleteMem() {
|
||||
int* x = new int; // No constructor
|
||||
*x = 6;
|
||||
delete x;
|
||||
}
|
||||
|
||||
class Base2 {
|
||||
public:
|
||||
void operator delete(void* p) {
|
||||
}
|
||||
virtual ~Base2() {};
|
||||
};
|
||||
|
||||
class Derived2 : public Base2 {
|
||||
int i;
|
||||
public:
|
||||
~Derived2() {};
|
||||
|
||||
void operator delete(void* p) {
|
||||
}
|
||||
};
|
||||
|
||||
// Delete is kind-of virtual in these cases
|
||||
int virtual_delete()
|
||||
{
|
||||
Base2* b1 = new Base2{};
|
||||
delete b1;
|
||||
|
||||
Base2* b2 = new Derived2{};
|
||||
delete b2;
|
||||
|
||||
Derived2* d = new Derived2{};
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
Reference in New Issue
Block a user