Skip to content

Commit e9db15f

Browse files
C++: IR translation for NewExpr and NewArrayExpr
These expressions are a little trickier than most because they include an implicit call to an allocator function. The database tells us which function to call, but we have to synthesize the allocation size and alignment arguments ourselves. The alignment argument, if it exists, is always a constant, but the size argument requires multiplication by the element count for most `NewArrayExpr`s. I introduced the new `TranslatedAllocationSize` class to handle this.
1 parent 2dc0928 commit e9db15f

File tree

9 files changed

+1273
-65
lines changed

9 files changed

+1273
-65
lines changed

cpp/ql/src/semmle/code/cpp/ir/internal/InstructionTag.qll

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ newtype TInstructionTag =
4343
SwitchBranchTag() or
4444
CallTargetTag() or
4545
CallTag() or
46+
AllocationSizeTag() or
47+
AllocationElementSizeTag() or
48+
AllocationExtentConvertTag() or
4649
ValueConditionConditionalBranchTag() or
4750
ConditionValueTrueTempAddressTag() or
4851
ConditionValueTrueConstantTag() or
@@ -88,11 +91,15 @@ string getInstructionTagId(TInstructionTag tag) {
8891
tag = OnlyInstructionTag() and result = "Only" or // Single instruction (not including implicit Load)
8992
tag = InitializerVariableAddressTag() and result = "InitVarAddr" or
9093
tag = InitializerStoreTag() and result = "InitStore" or
94+
tag = ZeroPadStringConstantTag() and result = "ZeroPadConst" or
95+
tag = ZeroPadStringElementIndexTag() and result = "ZeroPadElemIndex" or
96+
tag = ZeroPadStringElementAddressTag() and result = "ZeroPadElemAddr" or
97+
tag = ZeroPadStringStoreTag() and result = "ZeroPadStore" or
9198
tag = AssignOperationLoadTag() and result = "AssignOpLoad" or
9299
tag = AssignOperationConvertLeftTag() and result = "AssignOpConvLeft" or
93100
tag = AssignOperationOpTag() and result = "AssignOpOp" or
94101
tag = AssignOperationConvertResultTag() and result = "AssignOpConvRes" or
95-
tag = AssignmentStoreTag() and result = "AssigStore" or
102+
tag = AssignmentStoreTag() and result = "AssignStore" or
96103
tag = CrementLoadTag() and result = "CrementLoad" or
97104
tag = CrementConstantTag() and result = "CrementConst" or
98105
tag = CrementOpTag() and result = "CrementOp" or
@@ -106,6 +113,9 @@ string getInstructionTagId(TInstructionTag tag) {
106113
tag = SwitchBranchTag() and result = "SwitchBranch" or
107114
tag = CallTargetTag() and result = "CallTarget" or
108115
tag = CallTag() and result = "Call" or
116+
tag = AllocationSizeTag() and result = "AllocSize" or
117+
tag = AllocationElementSizeTag() and result = "AllocElemSize" or
118+
tag = AllocationExtentConvertTag() and result = "AllocExtConv" or
109119
tag = ValueConditionConditionalBranchTag() and result = "ValCondCondBranch" or
110120
tag = ConditionValueTrueTempAddressTag() and result = "CondValTrueTempAddr" or
111121
tag = ConditionValueTrueConstantTag() and result = "CondValTrueConst" or

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

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ private Element getRealParent(Expr expr) {
4747
}
4848

4949
/**
50-
* Holds if `expr` should be ignored for the purposes of code generation due to
51-
* some property of `expr` itself. Unlike `ignoreExpr()`, this predicate does
52-
* not ignore an expression solely because it is a descendant of an ignored
53-
* element.
50+
* Holds if `expr` and all of its descendants should be ignored for the purposes
51+
* of IR generation due to some property of `expr` itself. Unlike
52+
* `ignoreExpr()`, this predicate does not ignore an expression solely because
53+
* it is a descendant of an ignored element.
5454
*/
55-
private predicate ignoreExprLocal(Expr expr) {
55+
private predicate ignoreExprAndDescendants(Expr expr) {
5656
// Ignore parentless expressions
5757
not exists(getRealParent(expr)) or
5858
// Ignore the constants in SwitchCase, since their values are embedded in the
@@ -65,23 +65,32 @@ private predicate ignoreExprLocal(Expr expr) {
6565
// node as its qualifier, but that `FieldAccess` does not have a child of its own.
6666
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
6767
// context, much like we do with constructor calls.
68-
expr.getParent().(DestructorCall).getParent() instanceof DestructorFieldDestruction
68+
expr.getParent().(DestructorCall).getParent() instanceof DestructorFieldDestruction or
69+
exists(NewArrayExpr newExpr |
70+
// REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
71+
// represent them.
72+
newExpr.getInitializer().getFullyConverted() = expr
73+
)
6974
}
7075

7176
/**
72-
* Holds if `expr` should be ignored for the purposes of IR generation.
77+
* Holds if `expr` (not including its descendants) should be ignored for the
78+
* purposes of IR generation.
7379
*/
74-
private predicate ignoreExpr(Expr expr) {
75-
ignoreExprLocal(expr) or
76-
// Ignore all descendants of ignored elements as well.
77-
ignoreElement(getRealParent(expr))
80+
private predicate ignoreExprOnly(Expr expr) {
81+
exists(NewOrNewArrayExpr newExpr |
82+
// Ignore the allocator call, because we always synthesize it. Don't ignore
83+
// its arguments, though, because we use them as part of the synthesis.
84+
newExpr.getAllocatorCall() = expr
85+
)
7886
}
7987

8088
/**
81-
* Holds if `element` should be ignored for the purposes of IR generation.
89+
* Holds if `expr` should be ignored for the purposes of IR generation.
8290
*/
83-
private predicate ignoreElement(Element element) {
84-
ignoreExpr(element.(Expr))
91+
private predicate ignoreExpr(Expr expr) {
92+
ignoreExprOnly(expr) or
93+
ignoreExprAndDescendants(getRealParent*(expr))
8594
}
8695

8796
/**
@@ -216,6 +225,9 @@ newtype TTranslatedElement =
216225
exists(ConstructorFieldInit fieldInit |
217226
fieldInit.getExpr().getFullyConverted() = expr
218227
) or
228+
exists(NewExpr newExpr |
229+
newExpr.getInitializer().getFullyConverted() = expr
230+
) or
219231
exists(ThrowExpr throw |
220232
throw.getExpr().getFullyConverted() = expr
221233
)
@@ -298,6 +310,14 @@ newtype TTranslatedElement =
298310
exists(DeclStmt declStmt |
299311
declStmt.getADeclarationEntry() = entry
300312
)
313+
} or
314+
// An allocator call in a `new` or `new[]` expression
315+
TTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
316+
not ignoreExpr(newExpr)
317+
} or
318+
// An allocation size for a `new` or `new[]` expression
319+
TTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
320+
not ignoreExpr(newExpr)
301321
}
302322

303323
/**

0 commit comments

Comments
 (0)