mirror of
https://github.com/github/codeql.git
synced 2026-05-03 12:45:27 +02:00
Merge pull request #1551 from jbj/ir-DeleteExpr-placeholder
C++: Placeholder translation of delete expressions
This commit is contained in:
@@ -67,6 +67,12 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// Do not translate input/output variables in GNU asm statements
|
||||
getRealParent(expr) instanceof AsmStmt or
|
||||
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
|
||||
// We do not yet translate destructors properly, so for now we ignore any
|
||||
// custom deallocator call, if present.
|
||||
or
|
||||
exists(DeleteExpr deleteExpr | deleteExpr.getAllocatorCall() = expr)
|
||||
or
|
||||
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getAllocatorCall() = expr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +86,13 @@ private predicate ignoreExprOnly(Expr expr) {
|
||||
newExpr.getAllocatorCall() = expr
|
||||
) or
|
||||
not translateFunction(expr.getEnclosingFunction())
|
||||
or
|
||||
// We do not yet translate destructors properly, so for now we ignore the
|
||||
// destructor call. We do, however, translate the expression being
|
||||
// destructed, and that expression can be a child of the destructor call.
|
||||
exists(DeleteExpr deleteExpr | deleteExpr.getDestructorCall() = expr)
|
||||
or
|
||||
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getDestructorCall() = expr)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2561,6 +2561,88 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A placeholder for the translation of a `delete[]` expression.
|
||||
*
|
||||
* Proper translation is not yet implemented, but this stub implementation
|
||||
* ensures that code following a `delete[]` is not unreachable.
|
||||
*/
|
||||
class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionExpr {
|
||||
override DeleteArrayExpr expr;
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getOperand()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getOperand() and result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::NoOp
|
||||
}
|
||||
|
||||
private TranslatedExpr getOperand() {
|
||||
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A placeholder for the translation of a `delete` expression.
|
||||
*
|
||||
* Proper translation is not yet implemented, but this stub implementation
|
||||
* ensures that code following a `delete` is not unreachable.
|
||||
*/
|
||||
class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr {
|
||||
override DeleteExpr expr;
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getOperand()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getOperand() and result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::NoOp
|
||||
}
|
||||
|
||||
private TranslatedExpr getOperand() {
|
||||
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a `ConditionDeclExpr`, which represents the value of the declared variable
|
||||
* after conversion to `bool` in code such as:
|
||||
|
||||
@@ -12,12 +12,28 @@
|
||||
#-----| Type = void *
|
||||
#-----| 1: p#1
|
||||
#-----| Type = unsigned long
|
||||
#-----| void operator delete(void*, unsigned long, std::align_val_t)
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = void *
|
||||
#-----| 1: p#1
|
||||
#-----| Type = unsigned long
|
||||
#-----| 2: p#2
|
||||
#-----| Type = align_val_t
|
||||
#-----| void operator delete[](void*, unsigned long)
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = void *
|
||||
#-----| 1: p#1
|
||||
#-----| Type = unsigned long
|
||||
#-----| void operator delete[](void*, unsigned long, std::align_val_t)
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = void *
|
||||
#-----| 1: p#1
|
||||
#-----| Type = unsigned long
|
||||
#-----| 2: p#2
|
||||
#-----| Type = align_val_t
|
||||
#-----| void* operator new(unsigned long)
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
@@ -6647,6 +6663,162 @@ ir.cpp:
|
||||
# 1002| 0: (statement expression)
|
||||
# 1002| Type = int
|
||||
# 1002| ValueCategory = prvalue
|
||||
# 1006| void OperatorDelete()
|
||||
# 1006| params:
|
||||
# 1006| body: { ... }
|
||||
# 1007| 0: ExprStmt
|
||||
# 1007| 0: delete
|
||||
# 1007| Type = void
|
||||
# 1007| ValueCategory = prvalue
|
||||
# 1007| 3: static_cast<int *>...
|
||||
# 1007| Conversion = pointer conversion
|
||||
# 1007| Type = int *
|
||||
# 1007| Value = 0
|
||||
# 1007| ValueCategory = prvalue
|
||||
# 1007| expr: 0
|
||||
# 1007| Type = decltype(nullptr)
|
||||
# 1007| Value = 0
|
||||
# 1007| ValueCategory = prvalue
|
||||
# 1008| 1: ExprStmt
|
||||
# 1008| 0: delete
|
||||
# 1008| Type = void
|
||||
# 1008| ValueCategory = prvalue
|
||||
# 1008| 1: call to ~String
|
||||
# 1008| Type = void
|
||||
# 1008| ValueCategory = prvalue
|
||||
# 1008| -1: static_cast<String *>...
|
||||
# 1008| Conversion = pointer conversion
|
||||
# 1008| Type = String *
|
||||
# 1008| Value = 0
|
||||
# 1008| ValueCategory = prvalue
|
||||
# 1008| expr: 0
|
||||
# 1008| Type = decltype(nullptr)
|
||||
# 1008| Value = 0
|
||||
# 1008| ValueCategory = prvalue
|
||||
# 1009| 2: ExprStmt
|
||||
# 1009| 0: delete
|
||||
# 1009| Type = void
|
||||
# 1009| ValueCategory = prvalue
|
||||
# 1009| 0: call to operator delete
|
||||
# 1009| Type = void
|
||||
# 1009| ValueCategory = prvalue
|
||||
# 1009| 3: static_cast<SizedDealloc *>...
|
||||
# 1009| Conversion = pointer conversion
|
||||
# 1009| Type = SizedDealloc *
|
||||
# 1009| Value = 0
|
||||
# 1009| ValueCategory = prvalue
|
||||
# 1009| expr: 0
|
||||
# 1009| Type = decltype(nullptr)
|
||||
# 1009| Value = 0
|
||||
# 1009| ValueCategory = prvalue
|
||||
# 1010| 3: ExprStmt
|
||||
# 1010| 0: delete
|
||||
# 1010| Type = void
|
||||
# 1010| ValueCategory = prvalue
|
||||
# 1010| 3: static_cast<Overaligned *>...
|
||||
# 1010| Conversion = pointer conversion
|
||||
# 1010| Type = Overaligned *
|
||||
# 1010| Value = 0
|
||||
# 1010| ValueCategory = prvalue
|
||||
# 1010| expr: 0
|
||||
# 1010| Type = decltype(nullptr)
|
||||
# 1010| Value = 0
|
||||
# 1010| ValueCategory = prvalue
|
||||
# 1011| 4: ExprStmt
|
||||
# 1011| 0: delete
|
||||
# 1011| Type = void
|
||||
# 1011| ValueCategory = prvalue
|
||||
# 1011| 1: call to ~PolymorphicBase
|
||||
# 1011| Type = void
|
||||
# 1011| ValueCategory = prvalue
|
||||
# 1011| -1: static_cast<PolymorphicBase *>...
|
||||
# 1011| Conversion = pointer conversion
|
||||
# 1011| Type = PolymorphicBase *
|
||||
# 1011| Value = 0
|
||||
# 1011| ValueCategory = prvalue
|
||||
# 1011| expr: 0
|
||||
# 1011| Type = decltype(nullptr)
|
||||
# 1011| Value = 0
|
||||
# 1011| ValueCategory = prvalue
|
||||
# 1012| 5: return ...
|
||||
# 1015| void OperatorDeleteArray()
|
||||
# 1015| params:
|
||||
# 1015| body: { ... }
|
||||
# 1016| 0: ExprStmt
|
||||
# 1016| 0: delete[]
|
||||
# 1016| Type = void
|
||||
# 1016| ValueCategory = prvalue
|
||||
# 1016| 3: static_cast<int *>...
|
||||
# 1016| Conversion = pointer conversion
|
||||
# 1016| Type = int *
|
||||
# 1016| Value = 0
|
||||
# 1016| ValueCategory = prvalue
|
||||
# 1016| expr: 0
|
||||
# 1016| Type = decltype(nullptr)
|
||||
# 1016| Value = 0
|
||||
# 1016| ValueCategory = prvalue
|
||||
# 1017| 1: ExprStmt
|
||||
# 1017| 0: delete[]
|
||||
# 1017| Type = void
|
||||
# 1017| ValueCategory = prvalue
|
||||
# 1017| 1: call to ~String
|
||||
# 1017| Type = void
|
||||
# 1017| ValueCategory = prvalue
|
||||
# 1017| -1: static_cast<String *>...
|
||||
# 1017| Conversion = pointer conversion
|
||||
# 1017| Type = String *
|
||||
# 1017| Value = 0
|
||||
# 1017| ValueCategory = prvalue
|
||||
# 1017| expr: 0
|
||||
# 1017| Type = decltype(nullptr)
|
||||
# 1017| Value = 0
|
||||
# 1017| ValueCategory = prvalue
|
||||
# 1018| 2: ExprStmt
|
||||
# 1018| 0: delete[]
|
||||
# 1018| Type = void
|
||||
# 1018| ValueCategory = prvalue
|
||||
# 1018| 0: call to operator delete[]
|
||||
# 1018| Type = void
|
||||
# 1018| ValueCategory = prvalue
|
||||
# 1018| 3: static_cast<SizedDealloc *>...
|
||||
# 1018| Conversion = pointer conversion
|
||||
# 1018| Type = SizedDealloc *
|
||||
# 1018| Value = 0
|
||||
# 1018| ValueCategory = prvalue
|
||||
# 1018| expr: 0
|
||||
# 1018| Type = decltype(nullptr)
|
||||
# 1018| Value = 0
|
||||
# 1018| ValueCategory = prvalue
|
||||
# 1019| 3: ExprStmt
|
||||
# 1019| 0: delete[]
|
||||
# 1019| Type = void
|
||||
# 1019| ValueCategory = prvalue
|
||||
# 1019| 3: static_cast<Overaligned *>...
|
||||
# 1019| Conversion = pointer conversion
|
||||
# 1019| Type = Overaligned *
|
||||
# 1019| Value = 0
|
||||
# 1019| ValueCategory = prvalue
|
||||
# 1019| expr: 0
|
||||
# 1019| Type = decltype(nullptr)
|
||||
# 1019| Value = 0
|
||||
# 1019| ValueCategory = prvalue
|
||||
# 1020| 4: ExprStmt
|
||||
# 1020| 0: delete[]
|
||||
# 1020| Type = void
|
||||
# 1020| ValueCategory = prvalue
|
||||
# 1020| 1: call to ~PolymorphicBase
|
||||
# 1020| Type = void
|
||||
# 1020| ValueCategory = prvalue
|
||||
# 1020| -1: static_cast<PolymorphicBase *>...
|
||||
# 1020| Conversion = pointer conversion
|
||||
# 1020| Type = PolymorphicBase *
|
||||
# 1020| Value = 0
|
||||
# 1020| ValueCategory = prvalue
|
||||
# 1020| expr: 0
|
||||
# 1020| Type = decltype(nullptr)
|
||||
# 1020| Value = 0
|
||||
# 1020| ValueCategory = prvalue
|
||||
# 1021| 5: return ...
|
||||
# 1023| EmptyStruct& EmptyStruct::operator=(EmptyStruct const&)
|
||||
# 1023| params:
|
||||
#-----| 0: p#0
|
||||
|
||||
@@ -1002,7 +1002,7 @@ int ExprStmt(int b, int y, int z) {
|
||||
return ({x;});
|
||||
}
|
||||
|
||||
#if 0
|
||||
// TODO: `delete` gets translated to NoOp
|
||||
void OperatorDelete() {
|
||||
delete static_cast<int*>(nullptr); // No destructor
|
||||
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||
@@ -1011,6 +1011,7 @@ void OperatorDelete() {
|
||||
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||
}
|
||||
|
||||
// TODO: `delete[]` gets translated to NoOp
|
||||
void OperatorDeleteArray() {
|
||||
delete[] static_cast<int*>(nullptr); // No destructor
|
||||
delete[] static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||
@@ -1018,7 +1019,6 @@ void OperatorDeleteArray() {
|
||||
delete[] static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
|
||||
delete[] static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||
}
|
||||
#endif
|
||||
|
||||
struct EmptyStruct {};
|
||||
|
||||
|
||||
@@ -4418,6 +4418,46 @@ ir.cpp:
|
||||
# 991| v3_11(void) = UnmodeledUse : mu*
|
||||
# 991| v3_12(void) = ExitFunction :
|
||||
|
||||
# 1006| void OperatorDelete()
|
||||
# 1006| Block 0
|
||||
# 1006| v0_0(void) = EnterFunction :
|
||||
# 1006| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1006| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1007| r0_3(int *) = Constant[0] :
|
||||
# 1007| v0_4(void) = NoOp :
|
||||
# 1008| r0_5(String *) = Constant[0] :
|
||||
# 1008| v0_6(void) = NoOp :
|
||||
# 1009| r0_7(SizedDealloc *) = Constant[0] :
|
||||
# 1009| v0_8(void) = NoOp :
|
||||
# 1010| r0_9(Overaligned *) = Constant[0] :
|
||||
# 1010| v0_10(void) = NoOp :
|
||||
# 1011| r0_11(PolymorphicBase *) = Constant[0] :
|
||||
# 1011| v0_12(void) = NoOp :
|
||||
# 1012| v0_13(void) = NoOp :
|
||||
# 1006| v0_14(void) = ReturnVoid :
|
||||
# 1006| v0_15(void) = UnmodeledUse : mu*
|
||||
# 1006| v0_16(void) = ExitFunction :
|
||||
|
||||
# 1015| void OperatorDeleteArray()
|
||||
# 1015| Block 0
|
||||
# 1015| v0_0(void) = EnterFunction :
|
||||
# 1015| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1015| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1016| r0_3(int *) = Constant[0] :
|
||||
# 1016| v0_4(void) = NoOp :
|
||||
# 1017| r0_5(String *) = Constant[0] :
|
||||
# 1017| v0_6(void) = NoOp :
|
||||
# 1018| r0_7(SizedDealloc *) = Constant[0] :
|
||||
# 1018| v0_8(void) = NoOp :
|
||||
# 1019| r0_9(Overaligned *) = Constant[0] :
|
||||
# 1019| v0_10(void) = NoOp :
|
||||
# 1020| r0_11(PolymorphicBase *) = Constant[0] :
|
||||
# 1020| v0_12(void) = NoOp :
|
||||
# 1021| v0_13(void) = NoOp :
|
||||
# 1015| v0_14(void) = ReturnVoid :
|
||||
# 1015| v0_15(void) = UnmodeledUse : mu*
|
||||
# 1015| v0_16(void) = ExitFunction :
|
||||
|
||||
# 1025| void EmptyStructInit()
|
||||
# 1025| Block 0
|
||||
# 1025| v0_0(void) = EnterFunction :
|
||||
|
||||
Reference in New Issue
Block a user