Skip to content

Commit 45ba0c3

Browse files
authored
Merge pull request github#16907 from MathiasVP/phi-escape-5
C++: Add a new `MemoryLocation` to represent sets of `Allocation`s
2 parents 784a073 + 8a3a3fa commit 45ba0c3

29 files changed

+3169
-234
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ predicate ignoreInstruction(Instruction instr) {
4040
instr instanceof AliasedDefinitionInstruction or
4141
instr instanceof AliasedUseInstruction or
4242
instr instanceof InitializeNonLocalInstruction or
43-
instr instanceof ReturnIndirectionInstruction
43+
instr instanceof ReturnIndirectionInstruction or
44+
instr instanceof UninitializedGroupInstruction
4445
)
4546
}
4647

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ private newtype TMemoryAccessKind =
1313
TPhiMemoryAccess() or
1414
TUnmodeledMemoryAccess() or
1515
TChiTotalMemoryAccess() or
16-
TChiPartialMemoryAccess()
16+
TChiPartialMemoryAccess() or
17+
TGroupedMemoryAccess()
1718

1819
/**
1920
* Describes the set of memory locations memory accessed by a memory operand or
@@ -99,3 +100,11 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
99100
class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
100101
override string toString() { result = "chi(partial)" }
101102
}
103+
104+
/**
105+
* The result of an `UninitializedGroup` instruction, which initializes a set of
106+
* allocations that are each assigned the same virtual variable.
107+
*/
108+
class GroupedMemoryAccess extends MemoryAccessKind, TGroupedMemoryAccess {
109+
override string toString() { result = "group" }
110+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ private newtype TOpcode =
8989
TSizedBufferMayWriteSideEffect() or
9090
TInitializeDynamicAllocation() or
9191
TChi() or
92+
TUninitializedGroup() or
9293
TInlineAsm() or
9394
TUnreached() or
9495
TNewObj()
@@ -1237,6 +1238,17 @@ module Opcode {
12371238
}
12381239
}
12391240

1241+
/**
1242+
* The `Opcode` for a `UninitializedGroup`.
1243+
*
1244+
* See the `UninitializedGroupInstruction` documentation for more details.
1245+
*/
1246+
class UninitializedGroup extends Opcode, TUninitializedGroup {
1247+
final override string toString() { result = "UninitializedGroup" }
1248+
1249+
override GroupedMemoryAccess getWriteMemoryAccess() { any() }
1250+
}
1251+
12401252
/**
12411253
* The `Opcode` for an `InlineAsmInstruction`.
12421254
*

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
21422142
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
21432143
}
21442144

2145+
/**
2146+
* An instruction that initializes a set of allocations that are each assigned
2147+
* the same "virtual variable".
2148+
*
2149+
* As an example, consider the following snippet:
2150+
* ```
2151+
* int a;
2152+
* int b;
2153+
* int* p;
2154+
* if(b) {
2155+
* p = &a;
2156+
* } else {
2157+
* p = &b;
2158+
* }
2159+
* *p = 5;
2160+
* int x = a;
2161+
* ```
2162+
*
2163+
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
2164+
* analysis will create a region that contains both `a` and `b`. The region
2165+
* containing both `a` and `b` are initialized by an `UninitializedGroup`
2166+
* instruction in the entry block of the enclosing function.
2167+
*/
2168+
class UninitializedGroupInstruction extends Instruction {
2169+
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
2170+
2171+
/**
2172+
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
2173+
* Note: Allocations that are not represented as `IRVariable`s (such as
2174+
* dynamic allocations) are not returned by this predicate even if this
2175+
* instruction initializes such memory.
2176+
*/
2177+
final IRVariable getAnIRVariable() {
2178+
result = Construction::getAnUninitializedGroupVariable(this)
2179+
}
2180+
2181+
final override string getImmediateString() {
2182+
result = strictconcat(this.getAnIRVariable().toString(), ",")
2183+
}
2184+
}
2185+
21452186
/**
21462187
* An instruction representing unreachable code.
21472188
*

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ private predicate operandEscapesDomain(Operand operand) {
106106
not isArgumentForParameter(_, operand, _) and
107107
not isOnlyEscapesViaReturnArgument(operand) and
108108
not operand.getUse() instanceof ReturnValueInstruction and
109-
not operand.getUse() instanceof ReturnIndirectionInstruction and
110-
not operand instanceof PhiInputOperand
109+
not operand.getUse() instanceof ReturnIndirectionInstruction
111110
}
112111

113112
/**
@@ -191,6 +190,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
191190
// A copy propagates the source value.
192191
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
193192
)
193+
or
194+
operand = instr.(PhiInstruction).getAnInputOperand() and
195+
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
196+
// through the back edge of a loop (or through recursion).
197+
bitOffset = Ints::unknown()
194198
}
195199

196200
private predicate operandEscapesNonReturn(Operand operand) {
@@ -212,9 +216,6 @@ private predicate operandEscapesNonReturn(Operand operand) {
212216
or
213217
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
214218
or
215-
operand instanceof PhiInputOperand and
216-
resultEscapesNonReturn(operand.getUse())
217-
or
218219
operandEscapesDomain(operand)
219220
}
220221

@@ -236,9 +237,6 @@ private predicate operandMayReachReturn(Operand operand) {
236237
operand.getUse() instanceof ReturnValueInstruction
237238
or
238239
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
239-
or
240-
operand instanceof PhiInputOperand and
241-
resultMayReachReturn(operand.getUse())
242240
}
243241

244242
private predicate operandReturned(Operand operand, IntValue bitOffset) {

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 {

0 commit comments

Comments
 (0)