Skip to content

Commit 8349bd5

Browse files
authored
Merge pull request #21391 from jketema/jketema/nsdmi
C++: Handle field initialization via NSDMI in IR generation
2 parents 898d12b + ab1f0c1 commit 8349bd5

27 files changed

+2239
-292
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: feature
3+
---
4+
* Added a class `ConstructorDirectFieldInit` to represent field initializations that occur in member initializer lists.
5+
* Added a class `ConstructorDefaultFieldInit` to represent default field initializations.

cpp/ql/lib/semmle/code/cpp/exprs/Call.qll

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,15 @@ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit
585585

586586
/**
587587
* An initialization of a member variable performed as part of a
588-
* constructor's explicit initializer list or implicit actions.
588+
* constructor's initializer list or by default initialization.
589+
*
589590
* In the example below, member variable `b` is being initialized by
590-
* constructor parameter `a`:
591+
* constructor parameter `a`, and `c` is initialized by default
592+
* initialization:
591593
* ```
592594
* struct S {
593595
* int b;
596+
* int c = 3;
594597
* S(int a): b(a) {}
595598
* } s(2);
596599
* ```
@@ -616,6 +619,28 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
616619
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
617620
}
618621

622+
/**
623+
* An initialization of a member variable performed as part of a
624+
* constructor's explicit initializer list.
625+
*/
626+
class ConstructorDirectFieldInit extends ConstructorFieldInit {
627+
ConstructorDirectFieldInit() { exists(this.getChild(0)) }
628+
629+
override string getAPrimaryQlClass() { result = "ConstructorDirectFieldInit" }
630+
}
631+
632+
/**
633+
* An initialization of a member variable performed by default
634+
* initialization.
635+
*/
636+
class ConstructorDefaultFieldInit extends ConstructorFieldInit {
637+
ConstructorDefaultFieldInit() {
638+
not exists(this.getChild(0)) and exists(this.getTarget().getInitializer())
639+
}
640+
641+
override string getAPrimaryQlClass() { result = "ConstructorDefaultFieldInit" }
642+
}
643+
619644
/**
620645
* A call to a destructor of a base class or field as part of a destructor's
621646
* compiler-generated actions.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,11 @@ module Public {
878878

879879
/** Gets the parameter through which this value is assigned. */
880880
Parameter getParameter() {
881-
result = this.getCallInstruction().getStaticCallTarget().getParameter(this.getArgumentIndex())
881+
result =
882+
this.getCallInstruction()
883+
.getStaticCallTarget()
884+
.(Function)
885+
.getParameter(this.getArgumentIndex())
882886
}
883887
}
884888

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ private class PointerWrapperTypeIndirection extends Indirection instanceof Point
175175
override predicate isAdditionalDereference(Instruction deref, Operand address) {
176176
exists(CallInstruction call |
177177
operandForFullyConvertedCall(getAUse(deref), call) and
178-
this = call.getStaticCallTarget().getClassAndName(["operator*", "operator->", "get"]) and
178+
this =
179+
call.getStaticCallTarget().(Function).getClassAndName(["operator*", "operator->", "get"]) and
179180
address = call.getThisArgumentOperand()
180181
)
181182
}
@@ -194,7 +195,7 @@ private module IteratorIndirections {
194195

195196
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
196197
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
197-
this = call.getStaticCallTarget().getClassAndName("operator=") and
198+
this = call.getStaticCallTarget().(Function).getClassAndName("operator=") and
198199
address = call.getThisArgumentOperand() and
199200
certain = false
200201
)

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
495495
* `FunctionAddress` instruction.
496496
*/
497497
class FunctionInstruction extends Instruction {
498-
Language::Function funcSymbol;
498+
Language::Declaration funcSymbol;
499499

500500
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
501501

@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
504504
/**
505505
* Gets the function that this instruction references.
506506
*/
507-
final Language::Function getFunctionSymbol() { result = funcSymbol }
507+
final Language::Declaration getFunctionSymbol() { result = funcSymbol }
508508
}
509509

510510
/**
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
16781678
/**
16791679
* Gets the `Function` that the call targets, if this is statically known.
16801680
*/
1681-
final Language::Function getStaticCallTarget() {
1681+
final Language::Declaration getStaticCallTarget() {
16821682
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
16831683
}
16841684

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
495495
* `FunctionAddress` instruction.
496496
*/
497497
class FunctionInstruction extends Instruction {
498-
Language::Function funcSymbol;
498+
Language::Declaration funcSymbol;
499499

500500
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
501501

@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
504504
/**
505505
* Gets the function that this instruction references.
506506
*/
507-
final Language::Function getFunctionSymbol() { result = funcSymbol }
507+
final Language::Declaration getFunctionSymbol() { result = funcSymbol }
508508
}
509509

510510
/**
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
16781678
/**
16791679
* Gets the `Function` that the call targets, if this is statically known.
16801680
*/
1681-
final Language::Function getStaticCallTarget() {
1681+
final Language::Declaration getStaticCallTarget() {
16821682
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
16831683
}
16841684

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private import TranslatedCall
1515
private import TranslatedStmt
1616
private import TranslatedFunction
1717
private import TranslatedGlobalVar
18+
private import TranslatedNonStaticDataMember
1819
private import TranslatedInitialization
1920

2021
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
@@ -45,6 +46,9 @@ module Raw {
4546
or
4647
not var.isFromUninstantiatedTemplate(_) and
4748
var instanceof StaticInitializedStaticLocalVariable
49+
or
50+
not var.isFromUninstantiatedTemplate(_) and
51+
var instanceof Field
4852
) and
4953
var.hasInitializer() and
5054
(
@@ -64,6 +68,8 @@ module Raw {
6468
getTranslatedFunction(decl).hasUserVariable(var, type)
6569
or
6670
getTranslatedVarInit(decl).hasUserVariable(var, type)
71+
or
72+
getTranslatedFieldInit(decl).hasUserVariable(var, type)
6773
}
6874

6975
cached
@@ -110,7 +116,7 @@ module Raw {
110116
}
111117

112118
cached
113-
Function getInstructionFunction(Instruction instruction) {
119+
Declaration getInstructionFunction(Instruction instruction) {
114120
result =
115121
getInstructionTranslatedElement(instruction)
116122
.getInstructionFunction(getInstructionTag(instruction))

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

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,35 +130,39 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
130130
}
131131

132132
/**
133-
* A `Call` or `NewOrNewArrayExpr` or `DeleteOrDeleteArrayExpr`.
133+
* An expression that can have call side effects.
134134
*
135-
* All kinds of expression invoke a function as part of their evaluation. This class provides a
136-
* way to treat both kinds of function similarly, and to get the invoked `Function`.
135+
* All kinds of expressions invoke a function as part of their evaluation. This class provides a
136+
* way to treat those expressions similarly, and to get the invoked `Declaration`.
137137
*/
138-
class CallOrAllocationExpr extends Expr {
139-
CallOrAllocationExpr() {
138+
class ExprWithCallSideEffects extends Expr {
139+
ExprWithCallSideEffects() {
140140
this instanceof Call
141141
or
142142
this instanceof NewOrNewArrayExpr
143143
or
144144
this instanceof DeleteOrDeleteArrayExpr
145+
or
146+
this instanceof ConstructorDefaultFieldInit
145147
}
146148

147-
/** Gets the `Function` invoked by this expression, if known. */
148-
final Function getTarget() {
149+
/** Gets the `Declaration` invoked by this expression, if known. */
150+
final Declaration getTarget() {
149151
result = this.(Call).getTarget()
150152
or
151153
result = this.(NewOrNewArrayExpr).getAllocator()
152154
or
153155
result = this.(DeleteOrDeleteArrayExpr).getDeallocator()
156+
or
157+
result = this.(ConstructorDefaultFieldInit).getTarget()
154158
}
155159
}
156160

157161
/**
158162
* Returns the side effect opcode, if any, that represents any side effects not specifically modeled
159163
* by an argument side effect.
160164
*/
161-
Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
165+
Opcode getCallSideEffectOpcode(ExprWithCallSideEffects expr) {
162166
not exists(expr.getTarget().(SideEffectFunction)) and result instanceof Opcode::CallSideEffect
163167
or
164168
exists(SideEffectFunction sideEffectFunction |
@@ -175,7 +179,7 @@ Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
175179
/**
176180
* Returns a side effect opcode for parameter index `i` of the specified call.
177181
*
178-
* This predicate will return at most two results: one read side effect, and one write side effect.
182+
* This predicate will yield at most two results: one read side effect, and one write side effect.
179183
*/
180184
Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
181185
exists(boolean buffer |
@@ -228,3 +232,14 @@ Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
228232
)
229233
)
230234
}
235+
236+
/**
237+
* Returns a side effect opcode for a default field initialization.
238+
*
239+
* This predicate will yield two results: one read side effect, and one write side effect.
240+
*/
241+
Opcode getDefaultFieldInitSideEffectOpcode() {
242+
result instanceof Opcode::IndirectReadSideEffect
243+
or
244+
result instanceof Opcode::IndirectMayWriteSideEffect
245+
}

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

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ private import SideEffects
1010
private import TranslatedElement
1111
private import TranslatedExpr
1212
private import TranslatedFunction
13+
private import TranslatedInitialization
1314
private import DefaultOptions as DefaultOptions
1415

1516
/**
@@ -348,7 +349,7 @@ class TranslatedExprCall extends TranslatedCallExpr {
348349
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
349350
override FunctionCall expr;
350351

351-
override Function getInstructionFunction(InstructionTag tag) {
352+
override Declaration getInstructionFunction(InstructionTag tag) {
352353
tag = CallTargetTag() and result = expr.getTarget()
353354
}
354355

@@ -429,6 +430,9 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi
429430
or
430431
expr instanceof DeleteOrDeleteArrayExpr and
431432
result = getTranslatedDeleteOrDeleteArray(expr).getInstruction(CallTag())
433+
or
434+
expr instanceof ConstructorDefaultFieldInit and
435+
result = getTranslatedConstructorFieldInitialization(expr).getInstruction(CallTag())
432436
}
433437
}
434438

@@ -504,11 +508,25 @@ abstract class TranslatedSideEffect extends TranslatedElement {
504508
abstract predicate sideEffectInstruction(Opcode opcode, CppType type);
505509
}
506510

511+
private class CallOrDefaultFieldInit extends Expr {
512+
CallOrDefaultFieldInit() {
513+
this instanceof Call
514+
or
515+
this instanceof ConstructorDefaultFieldInit
516+
}
517+
518+
Declaration getTarget() {
519+
result = this.(Call).getTarget()
520+
or
521+
result = this.(ConstructorDefaultFieldInit).getTarget()
522+
}
523+
}
524+
507525
/**
508526
* The IR translation of a single argument side effect for a call.
509527
*/
510528
abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
511-
Call call;
529+
CallOrDefaultFieldInit callOrInit;
512530
int index;
513531
SideEffectOpcode sideEffectOpcode;
514532

@@ -524,7 +542,7 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
524542
result = "(read side effect for " + this.getArgString() + ")"
525543
}
526544

527-
override Call getPrimaryExpr() { result = call }
545+
override Expr getPrimaryExpr() { result = callOrInit }
528546

529547
override predicate sortOrder(int group, int indexInGroup) {
530548
indexInGroup = index and
@@ -586,9 +604,10 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
586604
tag instanceof OnlyInstructionTag and
587605
operandTag instanceof BufferSizeOperandTag and
588606
result =
589-
getTranslatedExpr(call.getArgument(call.getTarget()
590-
.(SideEffectFunction)
591-
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
607+
getTranslatedExpr(callOrInit
608+
.(Call)
609+
.getArgument(callOrInit.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
610+
.getFullyConverted()).getResult()
592611
}
593612

594613
/** Holds if this side effect is a write side effect, rather than a read side effect. */
@@ -616,7 +635,7 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
616635
Expr arg;
617636

618637
TranslatedArgumentExprSideEffect() {
619-
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
638+
this = TTranslatedArgumentExprSideEffect(callOrInit, arg, index, sideEffectOpcode)
620639
}
621640

622641
final override Locatable getAst() { result = arg }
@@ -640,28 +659,31 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
640659
* The IR translation of an argument side effect for `*this` on a call, where there is no `Expr`
641660
* object that represents the `this` argument.
642661
*
643-
* The applies only to constructor calls, as the AST has exploit qualifier `Expr`s for all other
644-
* calls to non-static member functions.
662+
* This applies to constructor calls and default field initializations, as the AST has explicit
663+
* qualifier `Expr`s for all other calls to non-static member functions.
645664
*/
646-
class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
647-
TTranslatedStructorQualifierSideEffect
665+
class TranslatedImplicitThisQualifierSideEffect extends TranslatedArgumentSideEffect,
666+
TTranslatedImplicitThisQualifierSideEffect
648667
{
649-
TranslatedStructorQualifierSideEffect() {
650-
this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
668+
TranslatedImplicitThisQualifierSideEffect() {
669+
this = TTranslatedImplicitThisQualifierSideEffect(callOrInit, sideEffectOpcode) and
651670
index = -1
652671
}
653672

654-
final override Locatable getAst() { result = call }
673+
final override Locatable getAst() { result = callOrInit }
655674

656-
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
675+
final override Type getIndirectionType() { result = callOrInit.getTarget().getDeclaringType() }
657676

658677
final override string getArgString() { result = "this" }
659678

660679
final override Instruction getArgInstruction() {
661680
exists(TranslatedStructorCall structorCall |
662-
structorCall.getExpr() = call and
681+
structorCall.getExpr() = callOrInit and
663682
result = structorCall.getQualifierResult()
664683
)
684+
or
685+
callOrInit instanceof ConstructorDefaultFieldInit and
686+
result = getTranslatedFunction(callOrInit.getEnclosingFunction()).getLoadThisInstruction()
665687
}
666688
}
667689

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ abstract class TranslatedCondition extends TranslatedElement {
3636
final override Declaration getFunction() {
3737
result = getEnclosingFunction(expr) or
3838
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
39-
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
39+
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable) or
40+
result = getEnclosingVariable(expr).(Field)
4041
}
4142

4243
final Type getResultType() { result = expr.getUnspecifiedType() }

0 commit comments

Comments
 (0)