Skip to content

Commit b98452d

Browse files
authored
Merge pull request #474 from rdmarsh2/rdmarsh/cpp/call-side-effect
C++: Initital aliased SSA with Chi nodes and function side effects
2 parents 4744cec + 40864f9 commit b98452d

40 files changed

+11737
-9033
lines changed

config/identical-files.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@
4343
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll",
4444
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll"
4545
],
46-
"C++ SSA SimpleSSA": [
47-
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll",
48-
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SimpleSSA.qll"
49-
],
50-
"C++ SSA IRBlockConstruction": [
51-
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockConstruction.qll",
52-
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockConstruction.qll"
53-
],
5446
"C++ SSA SSAConstruction": [
5547
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
5648
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll"

cpp/ql/src/semmle/code/cpp/PrintAST.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,42 @@ class FunctionNode extends ASTNode {
542542
}
543543
}
544544

545+
/**
546+
* A node representing an `ClassAggregateLiteral`.
547+
*/
548+
class ClassAggregateLiteralNode extends ExprNode {
549+
ClassAggregateLiteral list;
550+
551+
ClassAggregateLiteralNode() {
552+
list = ast
553+
}
554+
555+
override string getChildEdgeLabel(int childIndex) {
556+
exists(Field field |
557+
list.getFieldExpr(field) = list.getChild(childIndex) and
558+
result = "." + field.getName()
559+
)
560+
}
561+
}
562+
563+
/**
564+
* A node representing an `ArrayAggregateLiteral`.
565+
*/
566+
class ArrayAggregateLiteralNode extends ExprNode {
567+
ArrayAggregateLiteral list;
568+
569+
ArrayAggregateLiteralNode() {
570+
list = ast
571+
}
572+
573+
override string getChildEdgeLabel(int childIndex) {
574+
exists(int elementIndex |
575+
list.getElementExpr(elementIndex) = list.getChild(childIndex) and
576+
result = "[" + elementIndex.toString() + "]"
577+
)
578+
}
579+
}
580+
545581
query predicate nodes(PrintASTNode node, string key, string value) {
546582
node.shouldPrint() and
547583
value = node.getProperty(key)

cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import cpp
22

3-
newtype TMemoryAccessKind =
3+
private newtype TMemoryAccessKind =
44
TIndirectMemoryAccess() or
5+
TIndirectMayMemoryAccess() or
6+
TBufferMemoryAccess() or
7+
TBufferMayMemoryAccess() or
58
TEscapedMemoryAccess() or
69
TPhiMemoryAccess() or
7-
TUnmodeledMemoryAccess()
10+
TUnmodeledMemoryAccess() or
11+
TChiTotalMemoryAccess() or
12+
TChiPartialMemoryAccess()
813

914
/**
1015
* Describes the set of memory locations memory accessed by a memory operand or
@@ -15,15 +20,47 @@ class MemoryAccessKind extends TMemoryAccessKind {
1520
}
1621

1722
/**
18-
* The operand or result accesses memory at the address specified by the
19-
* `AddressOperand` on the same instruction.
23+
* The operand or result accesses memory at the address specified by the `AddressOperand` on the
24+
* same instruction.
2025
*/
2126
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
2227
override string toString() {
2328
result = "indirect"
2429
}
2530
}
2631

32+
/**
33+
* The operand or result may access some, all, or none of the memory at the address specified by the
34+
* `AddressOperand` on the same instruction.
35+
*/
36+
class IndirectMayMemoryAccess extends MemoryAccessKind, TIndirectMayMemoryAccess {
37+
override string toString() {
38+
result = "indirect(may)"
39+
}
40+
}
41+
42+
/**
43+
* The operand or result accesses memory starting at the address specified by the `AddressOperand`
44+
* on the same instruction, accessing a number of consecutive elements given by the
45+
* `BufferSizeOperand`.
46+
*/
47+
class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess {
48+
override string toString() {
49+
result = "buffer"
50+
}
51+
}
52+
53+
/**
54+
* The operand or result may access some, all, or none of the memory starting at the address
55+
* specified by the `AddressOperand` on the same instruction, accessing a number of consecutive
56+
* elements given by the `BufferSizeOperand`.
57+
*/
58+
class BufferMayMemoryAccess extends MemoryAccessKind, TBufferMayMemoryAccess {
59+
override string toString() {
60+
result = "buffer(may)"
61+
}
62+
}
63+
2764
/**
2865
* The operand or result accesses all memory whose address has escaped.
2966
*/
@@ -43,6 +80,26 @@ class PhiMemoryAccess extends MemoryAccessKind, TPhiMemoryAccess {
4380
}
4481
}
4582

83+
/**
84+
* The operand is a ChiTotal operand, which accesses the same memory as its
85+
* definition.
86+
*/
87+
class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
88+
override string toString() {
89+
result = "chi(total)"
90+
}
91+
}
92+
93+
/**
94+
* The operand is a ChiPartial operand, which accesses the same memory as its
95+
* definition.
96+
*/
97+
class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
98+
override string toString() {
99+
result = "chi(partial)"
100+
}
101+
}
102+
46103
/**
47104
* The operand accesses memory not modeled in SSA. Used only on the result of
48105
* `UnmodeledDefinition` and on the operands of `UnmodeledUse`.

cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,21 @@ private newtype TOpcode =
5454
TUnwind() or
5555
TUnmodeledDefinition() or
5656
TUnmodeledUse() or
57+
TAliasedDefinition() or
5758
TPhi() or
5859
TVarArgsStart() or
5960
TVarArgsEnd() or
6061
TVarArg() or
61-
TVarArgCopy()
62+
TVarArgCopy() or
63+
TCallSideEffect() or
64+
TCallReadSideEffect() or
65+
TIndirectReadSideEffect() or
66+
TIndirectWriteSideEffect() or
67+
TIndirectMayWriteSideEffect() or
68+
TBufferReadSideEffect() or
69+
TBufferWriteSideEffect() or
70+
TBufferMayWriteSideEffect() or
71+
TChi()
6272

6373
class Opcode extends TOpcode {
6474
string toString() {
@@ -92,6 +102,29 @@ abstract class OpcodeWithCondition extends Opcode {}
92102

93103
abstract class BuiltInOpcode extends Opcode {}
94104

105+
abstract class SideEffectOpcode extends Opcode {}
106+
107+
/**
108+
* An opcode that reads from a set of memory locations as a side effect.
109+
*/
110+
abstract class ReadSideEffectOpcode extends SideEffectOpcode {}
111+
112+
/**
113+
* An opcode that writes to a set of memory locations as a side effect.
114+
*/
115+
abstract class WriteSideEffectOpcode extends SideEffectOpcode {}
116+
117+
/**
118+
* An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled
119+
* as a read of the original contents, plus a "may" write of the new contents.
120+
*/
121+
abstract class MayWriteSideEffectOpcode extends SideEffectOpcode {}
122+
123+
/**
124+
* An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`.
125+
*/
126+
abstract class BufferAccessOpcode extends MemoryAccessOpcode {}
127+
95128
module Opcode {
96129
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
97130
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
@@ -148,9 +181,19 @@ module Opcode {
148181
class Unwind extends Opcode, TUnwind { override final string toString() { result = "Unwind" } }
149182
class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { override final string toString() { result = "UnmodeledDefinition" } }
150183
class UnmodeledUse extends Opcode, TUnmodeledUse { override final string toString() { result = "UnmodeledUse" } }
184+
class AliasedDefinition extends Opcode, TAliasedDefinition { override final string toString() { result = "AliasedDefinition" } }
151185
class Phi extends Opcode, TPhi { override final string toString() { result = "Phi" } }
152186
class VarArgsStart extends BuiltInOpcode, TVarArgsStart { override final string toString() { result = "VarArgsStart" } }
153187
class VarArgsEnd extends BuiltInOpcode, TVarArgsEnd { override final string toString() { result = "VarArgsEnd" } }
154188
class VarArg extends BuiltInOpcode, TVarArg { override final string toString() { result = "VarArg" } }
155189
class VarArgCopy extends BuiltInOpcode, TVarArgCopy { override final string toString() { result = "VarArgCopy" } }
190+
class CallSideEffect extends MayWriteSideEffectOpcode, TCallSideEffect { override final string toString() { result = "CallSideEffect" } }
191+
class CallReadSideEffect extends ReadSideEffectOpcode, TCallReadSideEffect { override final string toString() { result = "CallReadSideEffect" } }
192+
class IndirectReadSideEffect extends ReadSideEffectOpcode, MemoryAccessOpcode, TIndirectReadSideEffect { override final string toString() { result = "IndirectReadSideEffect" } }
193+
class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode, TIndirectWriteSideEffect { override final string toString() { result = "IndirectWriteSideEffect" } }
194+
class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode, TIndirectMayWriteSideEffect { override final string toString() { result = "IndirectMayWriteSideEffect" } }
195+
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect { override final string toString() { result = "BufferReadSideEffect" } }
196+
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, TBufferWriteSideEffect { override final string toString() { result = "BufferWriteSideEffect" } }
197+
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, TBufferMayWriteSideEffect { override final string toString() { result = "BufferMayWriteSideEffect" } }
198+
class Chi extends Opcode, TChi {override final string toString() { result = "Chi" } }
156199
}

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
private import internal.IRInternal
22
import Instruction
33
import semmle.code.cpp.ir.implementation.EdgeKind
4-
private import Construction::BlockConstruction
4+
import Cached
55

66
class IRBlock extends TIRBlock {
77
final string toString() {
@@ -98,3 +98,82 @@ class IRBlock extends TIRBlock {
9898
getAPredecessor().isReachableFromFunctionEntry()
9999
}
100100
}
101+
102+
private predicate startsBasicBlock(Instruction instr) {
103+
not instr instanceof PhiInstruction and
104+
(
105+
count(Instruction predecessor |
106+
instr = predecessor.getASuccessor()
107+
) != 1 or // Multiple predecessors or no predecessor
108+
exists(Instruction predecessor |
109+
instr = predecessor.getASuccessor() and
110+
strictcount(Instruction other |
111+
other = predecessor.getASuccessor()
112+
) > 1
113+
) or // Predecessor has multiple successors
114+
exists(Instruction predecessor, EdgeKind kind |
115+
instr = predecessor.getSuccessor(kind) and
116+
not kind instanceof GotoEdge
117+
) // Incoming edge is not a GotoEdge
118+
)
119+
}
120+
121+
private predicate isEntryBlock(TIRBlock block) {
122+
block = MkIRBlock(any(EnterFunctionInstruction enter))
123+
}
124+
125+
private cached module Cached {
126+
cached newtype TIRBlock =
127+
MkIRBlock(Instruction firstInstr) {
128+
startsBasicBlock(firstInstr)
129+
}
130+
131+
/** Holds if `i2` follows `i1` in a `IRBlock`. */
132+
private predicate adjacentInBlock(Instruction i1, Instruction i2) {
133+
exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and
134+
not startsBasicBlock(i2)
135+
}
136+
137+
/** Gets the index of `i` in its `IRBlock`. */
138+
private int getMemberIndex(Instruction i) {
139+
startsBasicBlock(i) and
140+
result = 0
141+
or
142+
exists(Instruction iPrev |
143+
adjacentInBlock(iPrev, i) and
144+
result = getMemberIndex(iPrev) + 1
145+
)
146+
}
147+
148+
/** Holds if `i` is the `index`th instruction in `block`. */
149+
cached Instruction getInstruction(TIRBlock block, int index) {
150+
exists(Instruction first |
151+
block = MkIRBlock(first) and
152+
index = getMemberIndex(result) and
153+
adjacentInBlock*(first, result)
154+
)
155+
}
156+
157+
cached int getInstructionCount(TIRBlock block) {
158+
result = strictcount(getInstruction(block, _))
159+
}
160+
161+
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
162+
exists(Instruction predLast, Instruction succFirst |
163+
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
164+
succFirst = predLast.getSuccessor(kind) and
165+
succ = MkIRBlock(succFirst)
166+
)
167+
}
168+
169+
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
170+
blockSuccessor(pred, succ, _)
171+
}
172+
173+
cached predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
174+
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
175+
}
176+
177+
Instruction getFirstInstruction(TIRBlock block) {
178+
block = MkIRBlock(result)
179+
}

0 commit comments

Comments
 (0)