Skip to content

Commit 58e993e

Browse files
authored
Merge pull request #82 from dave-bartolomeo/dave/NewDelete2
C++: IR generation for `new` and `new[]`
2 parents 04bccd0 + 72e7235 commit 58e993e

File tree

13 files changed

+2075
-856
lines changed

13 files changed

+2075
-856
lines changed

cpp/ql/src/semmle/code/cpp/exprs/Expr.qll

Lines changed: 44 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -581,24 +581,13 @@ class ReferenceDereferenceExpr extends Conversion, @ref_indirect {
581581
}
582582

583583
/**
584-
* A C++ `new` (non-array) expression.
584+
* A C++ `new` or `new[]` expression.
585585
*/
586-
class NewExpr extends Expr, @new_expr {
587-
override string toString() { result = "new" }
588-
586+
class NewOrNewArrayExpr extends Expr, @any_new_expr {
589587
override int getPrecedence() { result = 15 }
590588

591589
/**
592-
* Gets the type that is being allocated.
593-
*
594-
* For example, for `new int` the result is `int`.
595-
*/
596-
Type getAllocatedType() {
597-
new_allocated_type(underlyingElement(this), unresolveElement(result))
598-
}
599-
600-
/**
601-
* Gets the `operator new` that allocates storage.
590+
* Gets the `operator new` or `operator new[]` that allocates storage.
602591
*/
603592
Function getAllocator() {
604593
expr_allocator(underlyingElement(this), unresolveElement(result), _)
@@ -612,6 +601,21 @@ class NewExpr extends Expr, @new_expr {
612601
expr_allocator(underlyingElement(this), _, 1)
613602
}
614603

604+
/**
605+
* Gets the alignment argument passed to the allocation function, if any.
606+
*/
607+
Expr getAlignmentArgument() {
608+
hasAlignedAllocation() and
609+
(
610+
// If we have an allocator call, the alignment is the second argument to
611+
// that call.
612+
result = getAllocatorCall().getArgument(1) or
613+
// Otherwise, the alignment winds up as child number 3 of the `new`
614+
// itself.
615+
result = getChild(3)
616+
)
617+
}
618+
615619
/**
616620
* Gets the call to a non-default `operator new` that allocates storage, if any.
617621
*
@@ -652,6 +656,30 @@ class NewExpr extends Expr, @new_expr {
652656
)
653657
}
654658

659+
/**
660+
* Gets the type that is being allocated.
661+
*
662+
* For example, for `new int` the result is `int`.
663+
* For `new int[5]` the result is `int[5]`.
664+
*/
665+
abstract Type getAllocatedType();
666+
}
667+
668+
/**
669+
* A C++ `new` (non-array) expression.
670+
*/
671+
class NewExpr extends NewOrNewArrayExpr, @new_expr {
672+
override string toString() { result = "new" }
673+
674+
/**
675+
* Gets the type that is being allocated.
676+
*
677+
* For example, for `new int` the result is `int`.
678+
*/
679+
override Type getAllocatedType() {
680+
new_allocated_type(underlyingElement(this), unresolveElement(result))
681+
}
682+
655683
/**
656684
* Gets the call or expression that initializes the allocated object, if any.
657685
*
@@ -664,17 +692,15 @@ class NewExpr extends Expr, @new_expr {
664692
/**
665693
* A C++ `new[]` (array) expression.
666694
*/
667-
class NewArrayExpr extends Expr, @new_array_expr {
695+
class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
668696
override string toString() { result = "new[]" }
669697

670-
override int getPrecedence() { result = 15 }
671-
672698
/**
673699
* Gets the type that is being allocated.
674700
*
675701
* For example, for `new int[5]` the result is `int[5]`.
676702
*/
677-
Type getAllocatedType() {
703+
override Type getAllocatedType() {
678704
new_array_allocated_type(underlyingElement(this), unresolveElement(result))
679705
}
680706

@@ -685,56 +711,6 @@ class NewArrayExpr extends Expr, @new_array_expr {
685711
result = getType().getUnderlyingType().(PointerType).getBaseType()
686712
}
687713

688-
/**
689-
* Gets the `operator new[]` that allocates storage.
690-
*/
691-
Function getAllocator() {
692-
expr_allocator(underlyingElement(this), unresolveElement(result), _)
693-
}
694-
695-
/**
696-
* Holds if the allocation function is the version that expects an alignment
697-
* argument of type `std::align_val_t`.
698-
*/
699-
predicate hasAlignedAllocation() {
700-
expr_allocator(underlyingElement(this), _, 1)
701-
}
702-
703-
/**
704-
* Gets the call to a non-default `operator new[]` that allocates storage for the array, if any.
705-
*
706-
* If the default `operator new[]` is used, then there will be no call.
707-
*/
708-
FunctionCall getAllocatorCall() { result = this.getChild(0) }
709-
710-
/**
711-
* Gets the `operator delete` that deallocates storage if the initialization
712-
* throws an exception, if any.
713-
*/
714-
Function getDeallocator() {
715-
expr_deallocator(underlyingElement(this), unresolveElement(result), _)
716-
}
717-
718-
/**
719-
* Holds if the deallocation function expects a size argument.
720-
*/
721-
predicate hasSizedDeallocation() {
722-
exists(int form |
723-
expr_deallocator(underlyingElement(this), _, form) and
724-
form.bitAnd(1) != 0 // Bit zero is the "size" bit
725-
)
726-
}
727-
728-
/**
729-
* Holds if the deallocation function expects an alignment argument.
730-
*/
731-
predicate hasAlignedDeallocation() {
732-
exists(int form |
733-
expr_deallocator(underlyingElement(this), _, form) and
734-
form.bitAnd(2) != 0 // Bit one is the "alignment" bit
735-
)
736-
}
737-
738714
/**
739715
* Gets the call or expression that initializes the first element of the array, if any.
740716
*

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,11 @@ class Instruction extends Construction::TInstruction {
195195
private string getResultTypeString() {
196196
exists(string valcat |
197197
valcat = getValueCategoryString(resultType.toString()) and
198-
if resultType instanceof UnknownType and exists(getResultSize()) then
198+
if (resultType instanceof UnknownType and
199+
not isGLValue() and
200+
exists(getResultSize())) then (
199201
result = valcat + "[" + getResultSize().toString() + "]"
202+
)
200203
else
201204
result = valcat
202205
)

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: 35 additions & 15 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
/**
@@ -155,7 +164,7 @@ predicate ignoreLoad(Expr expr) {
155164

156165
newtype TTranslatedElement =
157166
// An expression that is not being consumed as a condition
158-
TTranslatedNonLoadExpr(Expr expr) {
167+
TTranslatedValueExpr(Expr expr) {
159168
not ignoreExpr(expr) and
160169
not isNativeCondition(expr) and
161170
not isFlexibleCondition(expr)
@@ -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)