Skip to content

Commit 689fda4

Browse files
committed
CPP: Add delete/delete[] calls to the IR.
1 parent dd27442 commit 689fda4

File tree

10 files changed

+244
-98
lines changed

10 files changed

+244
-98
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,17 @@ class CallOrAllocationExpr extends Expr {
130130
this instanceof Call
131131
or
132132
this instanceof NewOrNewArrayExpr
133+
or
134+
this instanceof DeleteOrDeleteArrayExpr
133135
}
134136

135137
/** Gets the `Function` invoked by this expression, if known. */
136138
final Function getTarget() {
137139
result = this.(Call).getTarget()
138140
or
139141
result = this.(NewOrNewArrayExpr).getAllocator()
142+
or
143+
result = this.(DeleteOrDeleteArrayExpr).getDeallocator()
140144
}
141145
}
142146

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi
350350
or
351351
expr instanceof NewOrNewArrayExpr and
352352
result = getTranslatedAllocatorCall(expr).getInstruction(CallTag())
353+
or
354+
expr instanceof DeleteOrDeleteArrayExpr and
355+
result = getTranslatedDeallocatorCall(expr).getInstruction(CallTag())
353356
}
354357
}
355358

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,18 @@ private predicate ignoreExprAndDescendants(Expr expr) {
7575
// REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
7676
// represent them.
7777
newExpr.getInitializer().getFullyConverted() = expr
78-
)
78+
) or
79+
exists(DeleteOrDeleteArrayExpr deleteExpr |
80+
// Ignore the deallocator call, because we always synthesize it.
81+
deleteExpr.getDeallocatorCall() = expr
82+
)
7983
or
8084
// Do not translate input/output variables in GNU asm statements
8185
// getRealParent(expr) instanceof AsmStmt
8286
// or
8387
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
8488
or
85-
// We do not yet translate destructors properly, so for now we ignore any
86-
// custom deallocator call, if present.
87-
exists(DeleteExpr deleteExpr | deleteExpr.getDeallocatorCall() = expr)
88-
or
89-
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getDeallocatorCall() = expr)
90-
or
89+
// va_start doesn't evaluate its argument, so we don't need to translate it.
9190
exists(BuiltInVarArgsStart vaStartExpr |
9291
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
9392
)
@@ -104,20 +103,19 @@ private predicate ignoreExprOnly(Expr expr) {
104103
newExpr.getAllocatorCall() = expr
105104
)
106105
or
106+
exists(DeleteOrDeleteArrayExpr deleteExpr |
107+
// Ignore the destructor call as we don't model it yet. Don't ignore
108+
// its arguments, though, as they are the arguments to the deallocator.
109+
deleteExpr.getDestructorCall() = expr
110+
)
111+
or
107112
// The extractor deliberately emits an `ErrorExpr` as the first argument to
108113
// the allocator call, if any, of a `NewOrNewArrayExpr`. That `ErrorExpr`
109114
// should not be translated.
110115
exists(NewOrNewArrayExpr new | expr = new.getAllocatorCall().getArgument(0))
111116
or
112117
not translateFunction(getEnclosingFunction(expr)) and
113118
not Raw::varHasIRFunc(getEnclosingVariable(expr))
114-
or
115-
// We do not yet translate destructors properly, so for now we ignore the
116-
// destructor call. We do, however, translate the expression being
117-
// destructed, and that expression can be a child of the destructor call.
118-
exists(DeleteExpr deleteExpr | deleteExpr.getDestructorCall() = expr)
119-
or
120-
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getDestructorCall() = expr)
121119
}
122120

123121
/**
@@ -724,6 +722,8 @@ newtype TTranslatedElement =
724722
} or
725723
// An allocator call in a `new` or `new[]` expression
726724
TTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) { not ignoreExpr(newExpr) } or
725+
// An deallocator call in a `delete` or `delete[]` expression
726+
TTranslatedDeallocatorCall(DeleteOrDeleteArrayExpr newExpr) { not ignoreExpr(newExpr) } or
727727
// An allocation size for a `new` or `new[]` expression
728728
TTranslatedAllocationSize(NewOrNewArrayExpr newExpr) { not ignoreExpr(newExpr) } or
729729
// The declaration/initialization part of a `ConditionDeclExpr`

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 73 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,48 @@ TranslatedAllocatorCall getTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
20172017
result.getAst() = newExpr
20182018
}
20192019

2020+
/**
2021+
* The IR translation of a call to `operator delete` as part of a `delete` or `delete[]`
2022+
* expression.
2023+
*/
2024+
class TranslatedDeallocatorCall extends TTranslatedDeallocatorCall, TranslatedDirectCall {
2025+
override DeleteOrDeleteArrayExpr expr;
2026+
2027+
TranslatedDeallocatorCall() { this = TTranslatedDeallocatorCall(expr) }
2028+
2029+
final override string toString() { result = "Deallocator call for " + expr.toString() }
2030+
2031+
final override predicate producesExprResult() { none() }
2032+
2033+
override Function getInstructionFunction(InstructionTag tag) {
2034+
tag = CallTargetTag() and result = expr.getDeallocator()
2035+
}
2036+
2037+
final override Type getCallResultType() { result = expr.getType() }
2038+
2039+
final override TranslatedExpr getQualifier() { none() }
2040+
2041+
final override predicate hasArguments() {
2042+
// All deallocator calls have at least one argument.
2043+
any()
2044+
}
2045+
2046+
final override int getNumberOfArguments() {
2047+
// We ignore the other arguments for now as we would have to synthesize them.
2048+
result = 1
2049+
}
2050+
2051+
final override TranslatedExpr getArgument(int index) {
2052+
// The only argument we define is the pointer to be deallocated.
2053+
index = 0 and
2054+
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
2055+
}
2056+
}
2057+
2058+
TranslatedDeallocatorCall getTranslatedDeallocatorCall(DeleteOrDeleteArrayExpr newExpr) {
2059+
result.getAst() = newExpr
2060+
}
2061+
20202062
/**
20212063
* Abstract class implemented by any `TranslatedElement` that has a child
20222064
* expression that is a call to a constructor or destructor, in order to
@@ -2955,75 +2997,60 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
29552997
}
29562998

29572999
/**
2958-
* A placeholder for the translation of a `delete[]` expression.
2959-
*
2960-
* Proper translation is not yet implemented, but this stub implementation
2961-
* ensures that code following a `delete[]` is not unreachable.
3000+
* The IR translation of a `delete` or `delete[]` expression.
29623001
*/
2963-
class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionExpr {
2964-
override DeleteArrayExpr expr;
3002+
abstract class TranslatedDeleteOrDeleteArrayExpr extends TranslatedNonConstantExpr {
3003+
override DeleteOrDeleteArrayExpr expr;
3004+
3005+
final override TranslatedElement getChild(int id) {
3006+
id = 0 and result = this.getDeallocatorCall()
3007+
}
3008+
3009+
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
3010+
tag = OnlyInstructionTag() and
3011+
opcode instanceof Opcode::Convert and
3012+
resultType = this.getResultType()
3013+
}
29653014

29663015
final override Instruction getFirstInstruction() {
2967-
result = this.getOperand().getFirstInstruction()
3016+
result = this.getDeallocatorCall().getFirstInstruction()
29683017
}
29693018

2970-
final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() }
3019+
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
29713020

29723021
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
3022+
kind instanceof GotoEdge and
29733023
tag = OnlyInstructionTag() and
2974-
result = this.getParent().getChildSuccessor(this) and
2975-
kind instanceof GotoEdge
3024+
result = this.getParent().getChildSuccessor(this)
29763025
}
29773026

29783027
final override Instruction getChildSuccessor(TranslatedElement child) {
2979-
child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag())
3028+
child = this.getDeallocatorCall() and result = this.getInstruction(OnlyInstructionTag())
29803029
}
29813030

29823031
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
2983-
none()
3032+
tag = OnlyInstructionTag() and
3033+
operandTag instanceof UnaryOperandTag and
3034+
result = this.getDeallocatorCall().getResult()
29843035
}
29853036

2986-
final override Opcode getOpcode() { result instanceof Opcode::NoOp }
2987-
2988-
private TranslatedExpr getOperand() {
2989-
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
3037+
private TranslatedDeallocatorCall getDeallocatorCall() {
3038+
result = getTranslatedDeallocatorCall(expr)
29903039
}
29913040
}
29923041

29933042
/**
2994-
* A placeholder for the translation of a `delete` expression.
2995-
*
2996-
* Proper translation is not yet implemented, but this stub implementation
2997-
* ensures that code following a `delete` is not unreachable.
3043+
* The IR translation of a `delete` expression.
29983044
*/
2999-
class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr {
3045+
class TranslatedDeleteExpr extends TranslatedDeleteOrDeleteArrayExpr {
30003046
override DeleteExpr expr;
3047+
}
30013048

3002-
final override Instruction getFirstInstruction() {
3003-
result = this.getOperand().getFirstInstruction()
3004-
}
3005-
3006-
final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() }
3007-
3008-
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
3009-
tag = OnlyInstructionTag() and
3010-
result = this.getParent().getChildSuccessor(this) and
3011-
kind instanceof GotoEdge
3012-
}
3013-
3014-
final override Instruction getChildSuccessor(TranslatedElement child) {
3015-
child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag())
3016-
}
3017-
3018-
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
3019-
none()
3020-
}
3021-
3022-
final override Opcode getOpcode() { result instanceof Opcode::NoOp }
3023-
3024-
private TranslatedExpr getOperand() {
3025-
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
3026-
}
3049+
/**
3050+
* The IR translation of a `delete[]` expression.
3051+
*/
3052+
class TranslatedDeleteArrayExpr extends TranslatedDeleteOrDeleteArrayExpr {
3053+
override DeleteArrayExpr expr;
30273054
}
30283055

30293056
/**

cpp/ql/test/library-tests/ir/ir/operand_locations.expected

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4887,10 +4887,70 @@
48874887
| ir.cpp:1011:12:1011:12 | Unary | r1011_3 |
48884888
| ir.cpp:1015:6:1015:19 | ChiPartial | partial:m1015_3 |
48894889
| ir.cpp:1015:6:1015:19 | ChiTotal | total:m1015_2 |
4890-
| ir.cpp:1015:6:1015:19 | SideEffect | m1015_3 |
4890+
| ir.cpp:1015:6:1015:19 | SideEffect | ~m1020_5 |
4891+
| ir.cpp:1016:3:1016:35 | CallTarget | func:r1016_1 |
4892+
| ir.cpp:1016:3:1016:35 | ChiPartial | partial:m1016_4 |
4893+
| ir.cpp:1016:3:1016:35 | ChiTotal | total:m1015_4 |
4894+
| ir.cpp:1016:3:1016:35 | SideEffect | ~m1015_4 |
4895+
| ir.cpp:1016:3:1016:35 | Unary | v1016_3 |
4896+
| ir.cpp:1016:10:1016:35 | Arg(0) | 0:r1016_2 |
4897+
| ir.cpp:1017:3:1017:38 | CallTarget | func:r1017_1 |
4898+
| ir.cpp:1017:3:1017:38 | ChiPartial | partial:m1017_4 |
4899+
| ir.cpp:1017:3:1017:38 | ChiTotal | total:m1016_5 |
4900+
| ir.cpp:1017:3:1017:38 | SideEffect | ~m1016_5 |
4901+
| ir.cpp:1017:3:1017:38 | Unary | v1017_3 |
4902+
| ir.cpp:1017:10:1017:38 | Arg(0) | 0:r1017_2 |
4903+
| ir.cpp:1018:3:1018:44 | CallTarget | func:r1018_1 |
4904+
| ir.cpp:1018:3:1018:44 | ChiPartial | partial:m1018_4 |
4905+
| ir.cpp:1018:3:1018:44 | ChiTotal | total:m1017_5 |
4906+
| ir.cpp:1018:3:1018:44 | SideEffect | ~m1017_5 |
4907+
| ir.cpp:1018:3:1018:44 | Unary | v1018_3 |
4908+
| ir.cpp:1018:10:1018:44 | Arg(0) | 0:r1018_2 |
4909+
| ir.cpp:1019:3:1019:43 | CallTarget | func:r1019_1 |
4910+
| ir.cpp:1019:3:1019:43 | ChiPartial | partial:m1019_4 |
4911+
| ir.cpp:1019:3:1019:43 | ChiTotal | total:m1018_5 |
4912+
| ir.cpp:1019:3:1019:43 | SideEffect | ~m1018_5 |
4913+
| ir.cpp:1019:3:1019:43 | Unary | v1019_3 |
4914+
| ir.cpp:1019:10:1019:43 | Arg(0) | 0:r1019_2 |
4915+
| ir.cpp:1020:3:1020:47 | CallTarget | func:r1020_1 |
4916+
| ir.cpp:1020:3:1020:47 | ChiPartial | partial:m1020_4 |
4917+
| ir.cpp:1020:3:1020:47 | ChiTotal | total:m1019_5 |
4918+
| ir.cpp:1020:3:1020:47 | SideEffect | ~m1019_5 |
4919+
| ir.cpp:1020:3:1020:47 | Unary | v1020_3 |
4920+
| ir.cpp:1020:10:1020:47 | Arg(0) | 0:r1020_2 |
48914921
| ir.cpp:1024:6:1024:24 | ChiPartial | partial:m1024_3 |
48924922
| ir.cpp:1024:6:1024:24 | ChiTotal | total:m1024_2 |
4893-
| ir.cpp:1024:6:1024:24 | SideEffect | m1024_3 |
4923+
| ir.cpp:1024:6:1024:24 | SideEffect | ~m1029_5 |
4924+
| ir.cpp:1025:3:1025:37 | CallTarget | func:r1025_1 |
4925+
| ir.cpp:1025:3:1025:37 | ChiPartial | partial:m1025_4 |
4926+
| ir.cpp:1025:3:1025:37 | ChiTotal | total:m1024_4 |
4927+
| ir.cpp:1025:3:1025:37 | SideEffect | ~m1024_4 |
4928+
| ir.cpp:1025:3:1025:37 | Unary | v1025_3 |
4929+
| ir.cpp:1025:12:1025:37 | Arg(0) | 0:r1025_2 |
4930+
| ir.cpp:1026:3:1026:40 | CallTarget | func:r1026_1 |
4931+
| ir.cpp:1026:3:1026:40 | ChiPartial | partial:m1026_4 |
4932+
| ir.cpp:1026:3:1026:40 | ChiTotal | total:m1025_5 |
4933+
| ir.cpp:1026:3:1026:40 | SideEffect | ~m1025_5 |
4934+
| ir.cpp:1026:3:1026:40 | Unary | v1026_3 |
4935+
| ir.cpp:1026:12:1026:40 | Arg(0) | 0:r1026_2 |
4936+
| ir.cpp:1027:3:1027:46 | CallTarget | func:r1027_1 |
4937+
| ir.cpp:1027:3:1027:46 | ChiPartial | partial:m1027_4 |
4938+
| ir.cpp:1027:3:1027:46 | ChiTotal | total:m1026_5 |
4939+
| ir.cpp:1027:3:1027:46 | SideEffect | ~m1026_5 |
4940+
| ir.cpp:1027:3:1027:46 | Unary | v1027_3 |
4941+
| ir.cpp:1027:12:1027:46 | Arg(0) | 0:r1027_2 |
4942+
| ir.cpp:1028:3:1028:45 | CallTarget | func:r1028_1 |
4943+
| ir.cpp:1028:3:1028:45 | ChiPartial | partial:m1028_4 |
4944+
| ir.cpp:1028:3:1028:45 | ChiTotal | total:m1027_5 |
4945+
| ir.cpp:1028:3:1028:45 | SideEffect | ~m1027_5 |
4946+
| ir.cpp:1028:3:1028:45 | Unary | v1028_3 |
4947+
| ir.cpp:1028:12:1028:45 | Arg(0) | 0:r1028_2 |
4948+
| ir.cpp:1029:3:1029:49 | CallTarget | func:r1029_1 |
4949+
| ir.cpp:1029:3:1029:49 | ChiPartial | partial:m1029_4 |
4950+
| ir.cpp:1029:3:1029:49 | ChiTotal | total:m1028_5 |
4951+
| ir.cpp:1029:3:1029:49 | SideEffect | ~m1028_5 |
4952+
| ir.cpp:1029:3:1029:49 | Unary | v1029_3 |
4953+
| ir.cpp:1029:12:1029:49 | Arg(0) | 0:r1029_2 |
48944954
| ir.cpp:1034:6:1034:20 | ChiPartial | partial:m1034_3 |
48954955
| ir.cpp:1034:6:1034:20 | ChiTotal | total:m1034_2 |
48964956
| ir.cpp:1034:6:1034:20 | SideEffect | m1034_3 |

0 commit comments

Comments
 (0)