Skip to content

Commit 03ec184

Browse files
committed
C++: Add 'InitializeGroup' instructions to the successor relation.
1 parent c4d72e5 commit 03ec184

File tree

3 files changed

+186
-8
lines changed

3 files changed

+186
-8
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
101101
final override predicate isAlwaysAllocatedOnStack() { none() }
102102

103103
final override predicate alwaysEscapes() { none() }
104+
105+
final IRAutomaticVariable getIRVariable() { result = var }
104106
}
105107

106108
class DynamicAllocation extends Allocation, TDynamicAllocation {

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,35 @@ private predicate hasOverlappingElement(NonSingletonSets s1, NonSingletonSets s2
9090
private module AllocationSet =
9191
QlBuiltins::EquivalenceRelation<NonSingletonSets, hasOverlappingElement/2>;
9292

93+
/**
94+
* Holds if `var` is created by the AST element `e`. Furthermore, the value `d`
95+
* represents which branch of the `Allocation` type `var` is from.
96+
*/
97+
private predicate allocationAst(Allocation var, @element e, int d) {
98+
var.(VariableAllocation).getIRVariable().getAst() = e and d = 0
99+
or
100+
var.(IndirectParameterAllocation).getIRVariable().getAst() = e and d = 1
101+
or
102+
var.(DynamicAllocation).getABaseInstruction().getAst() = e and d = 2
103+
}
104+
105+
/** Holds if `x = y` and `x` is an AST element that creates an `Allocation`. */
106+
private predicate id(@element x, @element y) {
107+
allocationAst(_, x, _) and
108+
x = y
109+
}
110+
111+
private predicate idOf(@element x, int y) = equivalenceRelation(id/2)(x, y)
112+
113+
/** Gets a unique integer representation of `var`. */
114+
private int getUniqueAllocationId(Allocation var) {
115+
exists(int r, @element e, int d |
116+
allocationAst(var, e, d) and
117+
idOf(e, r) and
118+
result = 3 * r + d
119+
)
120+
}
121+
93122
/**
94123
* An equivalence class of a set of allocations.
95124
*
@@ -135,6 +164,37 @@ class VariableGroup extends AllocationSet::EquivalenceClass {
135164
)
136165
}
137166

167+
/** Gets a unique string representing this set. */
168+
final private string getUniqueId() {
169+
result = strictconcat(getUniqueAllocationId(this.getAnAllocation()).toString(), ",")
170+
}
171+
172+
/**
173+
* Gets the order that this set should be initialized in.
174+
*
175+
* Note: This is _not_ the order in which the _members_ of the set should be
176+
* initialized. Rather, it represents the order in which the set should be
177+
* initialized in relation to other sets. That is, if
178+
* ```
179+
* getInitializationOrder() = 2
180+
* ```
181+
* then this set will be initialized as the second (third) set in the
182+
* enclosing function. In order words, the third `InitializeGroup`
183+
* instruction in the entry block of the enclosing function will initialize
184+
* this set of allocations.
185+
*/
186+
final int getInitializationOrder() {
187+
exists(IRFunction func |
188+
func = this.getIRFunction() and
189+
this =
190+
rank[result + 1](VariableGroup vg, string uniq |
191+
vg.getIRFunction() = func and uniq = vg.getUniqueId()
192+
|
193+
vg order by uniq
194+
)
195+
)
196+
}
197+
138198
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
139199
}
140200

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,43 @@ private class OldInstruction = Reachability::ReachableInstruction;
1515

1616
import Cached
1717

18+
/**
19+
* Holds if `instruction` is the first instruction that may be followed by
20+
* an `InitializeGroup` instruction, and the enclosing function of
21+
* `instruction` is `func`.
22+
*/
23+
private predicate isFirstInstructionBeforeInitializeGroup(Instruction instruction, IRFunction func) {
24+
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
25+
func = instruction.getEnclosingIRFunction()
26+
}
27+
28+
/** Gets the `i`'th `InitializeGroup` instruction in `func`. */
29+
private InitializeGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
30+
exists(Alias::VariableGroup vg |
31+
vg.getIRFunction() = func and
32+
vg.getInitializationOrder() = i and
33+
result = initializeGroup(vg)
34+
)
35+
}
36+
37+
/**
38+
* Holds if `instruction` is the last instruction in the chain of `InitializeGroup`
39+
* instructions in `func`. The chain of instructions may be empty in which case
40+
* `instruction` satisfies
41+
* ```
42+
* isFirstInstructionBeforeInitializeGroup(instruction, func)
43+
* ```
44+
*/
45+
predicate isLastInstructionForInitializeGroups(Instruction instruction, IRFunction func) {
46+
exists(int i |
47+
instruction = getInitGroupInstruction(i, func) and
48+
not exists(getInitGroupInstruction(i + 1, func))
49+
)
50+
or
51+
isFirstInstructionBeforeInitializeGroup(instruction, func) and
52+
not exists(getInitGroupInstruction(0, func))
53+
}
54+
1855
cached
1956
private module Cached {
2057
cached
@@ -356,14 +393,28 @@ private module Cached {
356393
)
357394
}
358395

359-
/*
360-
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
361-
* that node is its successor in the new successor relation, and the Chi node's successors are
362-
* the new instructions generated from the successors of the old instruction
363-
*/
396+
private InitializeGroupInstruction firstInstructionToInitializeGroup(
397+
Instruction instruction, EdgeKind kind
398+
) {
399+
exists(IRFunction func |
400+
isFirstInstructionBeforeInitializeGroup(instruction, func) and
401+
result = getInitGroupInstruction(0, func) and
402+
kind instanceof GotoEdge
403+
)
404+
}
364405

365-
cached
366-
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
406+
private Instruction getNextInitializeGroupInstruction(Instruction instruction, EdgeKind kind) {
407+
exists(int i, IRFunction func |
408+
func = instruction.getEnclosingIRFunction() and
409+
instruction = getInitGroupInstruction(i, func) and
410+
result = getInitGroupInstruction(i + 1, func) and
411+
kind instanceof GotoEdge
412+
)
413+
}
414+
415+
private Instruction getInstructionSuccessorAfterInitializeGroup0(
416+
Instruction instruction, EdgeKind kind
417+
) {
367418
if hasChiNode(_, getOldInstruction(instruction))
368419
then
369420
result = getChi(getOldInstruction(instruction)) and
@@ -383,6 +434,35 @@ private module Cached {
383434
)
384435
}
385436

437+
private Instruction getInstructionSuccessorAfterInitializeGroup(
438+
Instruction instruction, EdgeKind kind
439+
) {
440+
exists(IRFunction func, Instruction firstBeforeInitializeGroup |
441+
isLastInstructionForInitializeGroups(instruction, func) and
442+
isFirstInstructionBeforeInitializeGroup(firstBeforeInitializeGroup, func) and
443+
result = getInstructionSuccessorAfterInitializeGroup0(firstBeforeInitializeGroup, kind)
444+
)
445+
}
446+
447+
/**
448+
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
449+
* that node is its successor in the new successor relation, and the Chi node's successors are
450+
* the new instructions generated from the successors of the old instruction.
451+
*
452+
* Furthermore, the entry block is augmented with `InitializeGroup` instructions.
453+
*/
454+
cached
455+
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
456+
result = firstInstructionToInitializeGroup(instruction, kind)
457+
or
458+
result = getNextInitializeGroupInstruction(instruction, kind)
459+
or
460+
result = getInstructionSuccessorAfterInitializeGroup(instruction, kind)
461+
or
462+
not isFirstInstructionBeforeInitializeGroup(instruction, _) and
463+
result = getInstructionSuccessorAfterInitializeGroup0(instruction, kind)
464+
}
465+
386466
cached
387467
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
388468
exists(OldInstruction oldInstruction |
@@ -699,7 +779,13 @@ private import DefUse
699779
module DefUse {
700780
bindingset[index, block]
701781
pragma[inline_late]
702-
private int getNonChiOffset(int index, OldBlock block) { result = 2 * index }
782+
private int getNonChiOffset(int index, OldBlock block) {
783+
exists(IRFunction func | func = block.getEnclosingIRFunction() |
784+
if getNewBlock(block) = func.getEntryBlock()
785+
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
786+
else result = 2 * index
787+
)
788+
}
703789

704790
bindingset[index, block]
705791
pragma[inline_late]
@@ -736,6 +822,26 @@ module DefUse {
736822
hasDefinition(_, defLocation, defBlock, defOffset) and
737823
result = getPhi(defBlock, defLocation) and
738824
actualDefLocation = defLocation
825+
or
826+
exists(
827+
Alias::VariableGroup vg, int index, InitializeGroupInstruction initGroup,
828+
Alias::GroupedMemoryLocation gml
829+
|
830+
// Add 3 to account for the function prologue:
831+
// v1(void) = EnterFunction
832+
// m1(unknown) = AliasedDefinition
833+
// m2(unknown) = InitializeNonLocal
834+
index = 3 + vg.getInitializationOrder() and
835+
not gml.isMayAccess() and
836+
gml.isSome() and
837+
gml.getGroup() = vg and
838+
vg.getIRFunction().getEntryBlock() = defBlock and
839+
initGroup = initializeGroup(vg) and
840+
(defLocation = gml or defLocation = gml.getVirtualVariable()) and
841+
result = initGroup and
842+
defOffset = 2 * index and
843+
actualDefLocation = defLocation
844+
)
739845
}
740846

741847
/**
@@ -879,6 +985,16 @@ module DefUse {
879985
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
880986
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
881987
)
988+
or
989+
exists(InitializeGroupInstruction initGroup, int index, VariableGroup vg |
990+
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
991+
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
992+
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
993+
index = 3 + vg.getInitializationOrder() and
994+
initGroup = initializeGroup(vg) and
995+
exists(Alias::getOverlap(defLocation, useLocation)) and
996+
offset = 2 * index
997+
)
882998
}
883999

8841000
/**

0 commit comments

Comments
 (0)