Skip to content

Commit 52e0f3f

Browse files
Merge pull request #1551 from jbj/ir-DeleteExpr-placeholder
C++: Placeholder translation of delete expressions
2 parents 11581e4 + 6fe9945 commit 52e0f3f

File tree

5 files changed

+309
-2
lines changed

5 files changed

+309
-2
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ private predicate ignoreExprAndDescendants(Expr expr) {
6767
// Do not translate input/output variables in GNU asm statements
6868
getRealParent(expr) instanceof AsmStmt or
6969
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
70+
// We do not yet translate destructors properly, so for now we ignore any
71+
// custom deallocator call, if present.
72+
or
73+
exists(DeleteExpr deleteExpr | deleteExpr.getAllocatorCall() = expr)
74+
or
75+
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getAllocatorCall() = expr)
7076
}
7177

7278
/**
@@ -80,6 +86,13 @@ private predicate ignoreExprOnly(Expr expr) {
8086
newExpr.getAllocatorCall() = expr
8187
) or
8288
not translateFunction(expr.getEnclosingFunction())
89+
or
90+
// We do not yet translate destructors properly, so for now we ignore the
91+
// destructor call. We do, however, translate the expression being
92+
// destructed, and that expression can be a child of the destructor call.
93+
exists(DeleteExpr deleteExpr | deleteExpr.getDestructorCall() = expr)
94+
or
95+
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getDestructorCall() = expr)
8396
}
8497

8598
/**

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2561,6 +2561,88 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
25612561
}
25622562
}
25632563

2564+
/**
2565+
* A placeholder for the translation of a `delete[]` expression.
2566+
*
2567+
* Proper translation is not yet implemented, but this stub implementation
2568+
* ensures that code following a `delete[]` is not unreachable.
2569+
*/
2570+
class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionExpr {
2571+
override DeleteArrayExpr expr;
2572+
2573+
override final Instruction getFirstInstruction() {
2574+
result = getOperand().getFirstInstruction()
2575+
}
2576+
2577+
override final TranslatedElement getChild(int id) {
2578+
id = 0 and result = getOperand()
2579+
}
2580+
2581+
override final Instruction getInstructionSuccessor(InstructionTag tag,
2582+
EdgeKind kind) {
2583+
tag = OnlyInstructionTag() and
2584+
result = getParent().getChildSuccessor(this) and
2585+
kind instanceof GotoEdge
2586+
}
2587+
2588+
override final Instruction getChildSuccessor(TranslatedElement child) {
2589+
child = getOperand() and result = getInstruction(OnlyInstructionTag())
2590+
}
2591+
2592+
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
2593+
none()
2594+
}
2595+
2596+
override final Opcode getOpcode() {
2597+
result instanceof Opcode::NoOp
2598+
}
2599+
2600+
private TranslatedExpr getOperand() {
2601+
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
2602+
}
2603+
}
2604+
2605+
/**
2606+
* A placeholder for the translation of a `delete` expression.
2607+
*
2608+
* Proper translation is not yet implemented, but this stub implementation
2609+
* ensures that code following a `delete` is not unreachable.
2610+
*/
2611+
class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr {
2612+
override DeleteExpr expr;
2613+
2614+
override final Instruction getFirstInstruction() {
2615+
result = getOperand().getFirstInstruction()
2616+
}
2617+
2618+
override final TranslatedElement getChild(int id) {
2619+
id = 0 and result = getOperand()
2620+
}
2621+
2622+
override final Instruction getInstructionSuccessor(InstructionTag tag,
2623+
EdgeKind kind) {
2624+
tag = OnlyInstructionTag() and
2625+
result = getParent().getChildSuccessor(this) and
2626+
kind instanceof GotoEdge
2627+
}
2628+
2629+
override final Instruction getChildSuccessor(TranslatedElement child) {
2630+
child = getOperand() and result = getInstruction(OnlyInstructionTag())
2631+
}
2632+
2633+
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
2634+
none()
2635+
}
2636+
2637+
override final Opcode getOpcode() {
2638+
result instanceof Opcode::NoOp
2639+
}
2640+
2641+
private TranslatedExpr getOperand() {
2642+
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
2643+
}
2644+
}
2645+
25642646
/**
25652647
* The IR translation of a `ConditionDeclExpr`, which represents the value of the declared variable
25662648
* after conversion to `bool` in code such as:

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

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,28 @@
1212
#-----| Type = void *
1313
#-----| 1: p#1
1414
#-----| Type = unsigned long
15+
#-----| void operator delete(void*, unsigned long, std::align_val_t)
16+
#-----| params:
17+
#-----| 0: p#0
18+
#-----| Type = void *
19+
#-----| 1: p#1
20+
#-----| Type = unsigned long
21+
#-----| 2: p#2
22+
#-----| Type = align_val_t
1523
#-----| void operator delete[](void*, unsigned long)
1624
#-----| params:
1725
#-----| 0: p#0
1826
#-----| Type = void *
1927
#-----| 1: p#1
2028
#-----| Type = unsigned long
29+
#-----| void operator delete[](void*, unsigned long, std::align_val_t)
30+
#-----| params:
31+
#-----| 0: p#0
32+
#-----| Type = void *
33+
#-----| 1: p#1
34+
#-----| Type = unsigned long
35+
#-----| 2: p#2
36+
#-----| Type = align_val_t
2137
#-----| void* operator new(unsigned long)
2238
#-----| params:
2339
#-----| 0: p#0
@@ -6647,6 +6663,162 @@ ir.cpp:
66476663
# 1002| 0: (statement expression)
66486664
# 1002| Type = int
66496665
# 1002| ValueCategory = prvalue
6666+
# 1006| void OperatorDelete()
6667+
# 1006| params:
6668+
# 1006| body: { ... }
6669+
# 1007| 0: ExprStmt
6670+
# 1007| 0: delete
6671+
# 1007| Type = void
6672+
# 1007| ValueCategory = prvalue
6673+
# 1007| 3: static_cast<int *>...
6674+
# 1007| Conversion = pointer conversion
6675+
# 1007| Type = int *
6676+
# 1007| Value = 0
6677+
# 1007| ValueCategory = prvalue
6678+
# 1007| expr: 0
6679+
# 1007| Type = decltype(nullptr)
6680+
# 1007| Value = 0
6681+
# 1007| ValueCategory = prvalue
6682+
# 1008| 1: ExprStmt
6683+
# 1008| 0: delete
6684+
# 1008| Type = void
6685+
# 1008| ValueCategory = prvalue
6686+
# 1008| 1: call to ~String
6687+
# 1008| Type = void
6688+
# 1008| ValueCategory = prvalue
6689+
# 1008| -1: static_cast<String *>...
6690+
# 1008| Conversion = pointer conversion
6691+
# 1008| Type = String *
6692+
# 1008| Value = 0
6693+
# 1008| ValueCategory = prvalue
6694+
# 1008| expr: 0
6695+
# 1008| Type = decltype(nullptr)
6696+
# 1008| Value = 0
6697+
# 1008| ValueCategory = prvalue
6698+
# 1009| 2: ExprStmt
6699+
# 1009| 0: delete
6700+
# 1009| Type = void
6701+
# 1009| ValueCategory = prvalue
6702+
# 1009| 0: call to operator delete
6703+
# 1009| Type = void
6704+
# 1009| ValueCategory = prvalue
6705+
# 1009| 3: static_cast<SizedDealloc *>...
6706+
# 1009| Conversion = pointer conversion
6707+
# 1009| Type = SizedDealloc *
6708+
# 1009| Value = 0
6709+
# 1009| ValueCategory = prvalue
6710+
# 1009| expr: 0
6711+
# 1009| Type = decltype(nullptr)
6712+
# 1009| Value = 0
6713+
# 1009| ValueCategory = prvalue
6714+
# 1010| 3: ExprStmt
6715+
# 1010| 0: delete
6716+
# 1010| Type = void
6717+
# 1010| ValueCategory = prvalue
6718+
# 1010| 3: static_cast<Overaligned *>...
6719+
# 1010| Conversion = pointer conversion
6720+
# 1010| Type = Overaligned *
6721+
# 1010| Value = 0
6722+
# 1010| ValueCategory = prvalue
6723+
# 1010| expr: 0
6724+
# 1010| Type = decltype(nullptr)
6725+
# 1010| Value = 0
6726+
# 1010| ValueCategory = prvalue
6727+
# 1011| 4: ExprStmt
6728+
# 1011| 0: delete
6729+
# 1011| Type = void
6730+
# 1011| ValueCategory = prvalue
6731+
# 1011| 1: call to ~PolymorphicBase
6732+
# 1011| Type = void
6733+
# 1011| ValueCategory = prvalue
6734+
# 1011| -1: static_cast<PolymorphicBase *>...
6735+
# 1011| Conversion = pointer conversion
6736+
# 1011| Type = PolymorphicBase *
6737+
# 1011| Value = 0
6738+
# 1011| ValueCategory = prvalue
6739+
# 1011| expr: 0
6740+
# 1011| Type = decltype(nullptr)
6741+
# 1011| Value = 0
6742+
# 1011| ValueCategory = prvalue
6743+
# 1012| 5: return ...
6744+
# 1015| void OperatorDeleteArray()
6745+
# 1015| params:
6746+
# 1015| body: { ... }
6747+
# 1016| 0: ExprStmt
6748+
# 1016| 0: delete[]
6749+
# 1016| Type = void
6750+
# 1016| ValueCategory = prvalue
6751+
# 1016| 3: static_cast<int *>...
6752+
# 1016| Conversion = pointer conversion
6753+
# 1016| Type = int *
6754+
# 1016| Value = 0
6755+
# 1016| ValueCategory = prvalue
6756+
# 1016| expr: 0
6757+
# 1016| Type = decltype(nullptr)
6758+
# 1016| Value = 0
6759+
# 1016| ValueCategory = prvalue
6760+
# 1017| 1: ExprStmt
6761+
# 1017| 0: delete[]
6762+
# 1017| Type = void
6763+
# 1017| ValueCategory = prvalue
6764+
# 1017| 1: call to ~String
6765+
# 1017| Type = void
6766+
# 1017| ValueCategory = prvalue
6767+
# 1017| -1: static_cast<String *>...
6768+
# 1017| Conversion = pointer conversion
6769+
# 1017| Type = String *
6770+
# 1017| Value = 0
6771+
# 1017| ValueCategory = prvalue
6772+
# 1017| expr: 0
6773+
# 1017| Type = decltype(nullptr)
6774+
# 1017| Value = 0
6775+
# 1017| ValueCategory = prvalue
6776+
# 1018| 2: ExprStmt
6777+
# 1018| 0: delete[]
6778+
# 1018| Type = void
6779+
# 1018| ValueCategory = prvalue
6780+
# 1018| 0: call to operator delete[]
6781+
# 1018| Type = void
6782+
# 1018| ValueCategory = prvalue
6783+
# 1018| 3: static_cast<SizedDealloc *>...
6784+
# 1018| Conversion = pointer conversion
6785+
# 1018| Type = SizedDealloc *
6786+
# 1018| Value = 0
6787+
# 1018| ValueCategory = prvalue
6788+
# 1018| expr: 0
6789+
# 1018| Type = decltype(nullptr)
6790+
# 1018| Value = 0
6791+
# 1018| ValueCategory = prvalue
6792+
# 1019| 3: ExprStmt
6793+
# 1019| 0: delete[]
6794+
# 1019| Type = void
6795+
# 1019| ValueCategory = prvalue
6796+
# 1019| 3: static_cast<Overaligned *>...
6797+
# 1019| Conversion = pointer conversion
6798+
# 1019| Type = Overaligned *
6799+
# 1019| Value = 0
6800+
# 1019| ValueCategory = prvalue
6801+
# 1019| expr: 0
6802+
# 1019| Type = decltype(nullptr)
6803+
# 1019| Value = 0
6804+
# 1019| ValueCategory = prvalue
6805+
# 1020| 4: ExprStmt
6806+
# 1020| 0: delete[]
6807+
# 1020| Type = void
6808+
# 1020| ValueCategory = prvalue
6809+
# 1020| 1: call to ~PolymorphicBase
6810+
# 1020| Type = void
6811+
# 1020| ValueCategory = prvalue
6812+
# 1020| -1: static_cast<PolymorphicBase *>...
6813+
# 1020| Conversion = pointer conversion
6814+
# 1020| Type = PolymorphicBase *
6815+
# 1020| Value = 0
6816+
# 1020| ValueCategory = prvalue
6817+
# 1020| expr: 0
6818+
# 1020| Type = decltype(nullptr)
6819+
# 1020| Value = 0
6820+
# 1020| ValueCategory = prvalue
6821+
# 1021| 5: return ...
66506822
# 1023| EmptyStruct& EmptyStruct::operator=(EmptyStruct const&)
66516823
# 1023| params:
66526824
#-----| 0: p#0

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ int ExprStmt(int b, int y, int z) {
10021002
return ({x;});
10031003
}
10041004

1005-
#if 0
1005+
// TODO: `delete` gets translated to NoOp
10061006
void OperatorDelete() {
10071007
delete static_cast<int*>(nullptr); // No destructor
10081008
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
@@ -1011,14 +1011,14 @@ void OperatorDelete() {
10111011
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
10121012
}
10131013

1014+
// TODO: `delete[]` gets translated to NoOp
10141015
void OperatorDeleteArray() {
10151016
delete[] static_cast<int*>(nullptr); // No destructor
10161017
delete[] static_cast<String*>(nullptr); // Non-virtual destructor, with size.
10171018
delete[] static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
10181019
delete[] static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
10191020
delete[] static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
10201021
}
1021-
#endif
10221022

10231023
struct EmptyStruct {};
10241024

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4418,6 +4418,46 @@ ir.cpp:
44184418
# 991| v3_11(void) = UnmodeledUse : mu*
44194419
# 991| v3_12(void) = ExitFunction :
44204420

4421+
# 1006| void OperatorDelete()
4422+
# 1006| Block 0
4423+
# 1006| v0_0(void) = EnterFunction :
4424+
# 1006| mu0_1(unknown) = AliasedDefinition :
4425+
# 1006| mu0_2(unknown) = UnmodeledDefinition :
4426+
# 1007| r0_3(int *) = Constant[0] :
4427+
# 1007| v0_4(void) = NoOp :
4428+
# 1008| r0_5(String *) = Constant[0] :
4429+
# 1008| v0_6(void) = NoOp :
4430+
# 1009| r0_7(SizedDealloc *) = Constant[0] :
4431+
# 1009| v0_8(void) = NoOp :
4432+
# 1010| r0_9(Overaligned *) = Constant[0] :
4433+
# 1010| v0_10(void) = NoOp :
4434+
# 1011| r0_11(PolymorphicBase *) = Constant[0] :
4435+
# 1011| v0_12(void) = NoOp :
4436+
# 1012| v0_13(void) = NoOp :
4437+
# 1006| v0_14(void) = ReturnVoid :
4438+
# 1006| v0_15(void) = UnmodeledUse : mu*
4439+
# 1006| v0_16(void) = ExitFunction :
4440+
4441+
# 1015| void OperatorDeleteArray()
4442+
# 1015| Block 0
4443+
# 1015| v0_0(void) = EnterFunction :
4444+
# 1015| mu0_1(unknown) = AliasedDefinition :
4445+
# 1015| mu0_2(unknown) = UnmodeledDefinition :
4446+
# 1016| r0_3(int *) = Constant[0] :
4447+
# 1016| v0_4(void) = NoOp :
4448+
# 1017| r0_5(String *) = Constant[0] :
4449+
# 1017| v0_6(void) = NoOp :
4450+
# 1018| r0_7(SizedDealloc *) = Constant[0] :
4451+
# 1018| v0_8(void) = NoOp :
4452+
# 1019| r0_9(Overaligned *) = Constant[0] :
4453+
# 1019| v0_10(void) = NoOp :
4454+
# 1020| r0_11(PolymorphicBase *) = Constant[0] :
4455+
# 1020| v0_12(void) = NoOp :
4456+
# 1021| v0_13(void) = NoOp :
4457+
# 1015| v0_14(void) = ReturnVoid :
4458+
# 1015| v0_15(void) = UnmodeledUse : mu*
4459+
# 1015| v0_16(void) = ExitFunction :
4460+
44214461
# 1025| void EmptyStructInit()
44224462
# 1025| Block 0
44234463
# 1025| v0_0(void) = EnterFunction :

0 commit comments

Comments
 (0)