Skip to content

Commit f6f9afe

Browse files
committed
C++: Implement Instruction.isResultConflated
This predicate replaces `isChiForAllAliasedMemory`, which was always intended to be temporary. A test is added to `IRSanity.qll` to verify that the new predicate corresponds exactly with (a fixed version of) the old one. The implementation of the new predicate, `Cached::hasConflatedMemoryResult` in `SSAConstruction.qll`, is faster to compute than the old `isChiForAllAliasedMemory` because it uses information that's readily available during SSA construction.
1 parent 67cb852 commit f6f9afe

26 files changed

Lines changed: 314 additions & 14 deletions

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
183183
i2.(UnaryInstruction).getUnary() = i1
184184
or
185185
i2.(ChiInstruction).getPartial() = i1 and
186-
not isChiForAllAliasedMemory(i2)
186+
not i2.isResultConflated()
187187
or
188188
exists(BinaryInstruction bin |
189189
bin = i2 and
@@ -276,19 +276,6 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
276276
)
277277
}
278278

279-
/**
280-
* Holds if `chi` is on the chain of chi-instructions for all aliased memory.
281-
* Taint should not pass through these instructions since they tend to mix up
282-
* unrelated objects.
283-
*/
284-
private predicate isChiForAllAliasedMemory(Instruction instr) {
285-
instr.(ChiInstruction).getTotal() instanceof AliasedDefinitionInstruction
286-
or
287-
isChiForAllAliasedMemory(instr.(ChiInstruction).getTotal())
288-
or
289-
isChiForAllAliasedMemory(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
290-
}
291-
292279
private predicate modelTaintToReturnValue(Function f, int parameterIn) {
293280
// Taint flow from parameter to return value
294281
exists(FunctionInput modelIn, FunctionOutput modelOut |

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,34 @@ module InstructionSanity {
272272
func = switchInstr.getEnclosingIRFunction() and
273273
funcText = Language::getIdentityString(func.getFunction())
274274
}
275+
276+
/**
277+
* Holds if `instr` is on the chain of chi/phi instructions for all aliased
278+
* memory.
279+
*/
280+
private predicate isOnAliasedDefinitionChain(Instruction instr) {
281+
instr instanceof AliasedDefinitionInstruction
282+
or
283+
instr.getOpcode() instanceof Opcode::InitializeNonLocal
284+
or
285+
isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal())
286+
or
287+
isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
288+
}
289+
290+
private predicate shouldBeConflated(Instruction instr) {
291+
isOnAliasedDefinitionChain(instr)
292+
or
293+
instr instanceof UnmodeledDefinitionInstruction
294+
}
295+
296+
query predicate notMarkedAsConflated(Instruction instr) {
297+
shouldBeConflated(instr) and
298+
not instr.isResultConflated()
299+
}
300+
301+
query predicate wronglyMarkedAsConflated(Instruction instr) {
302+
instr.isResultConflated() and
303+
not shouldBeConflated(instr)
304+
}
275305
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ class Instruction extends Construction::TInstruction {
321321
Construction::hasModeledMemoryResult(this)
322322
}
323323

324+
/**
325+
* Holds if this is an instruction with a memory result that represents a
326+
* conflation of more than one object.
327+
*
328+
* This happens in practice when dereferencing a pointer that cannot be
329+
* tracked back to a single local allocation. Such memory is instead modeled
330+
* as originating on the `AliasedDefinitionInstruction` at the entry of the
331+
* function.
332+
*/
333+
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
334+
324335
/**
325336
* Gets the successor of this instruction along the control flow edge
326337
* specified by `kind`.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
354354
final override predicate isMayAccess() { isMayAccess = true }
355355
}
356356

357+
/** A virtual variable that groups all escaped memory within a function. */
357358
class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
358359
AliasedVirtualVariable() { not isMayAccess() }
359360
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,30 @@ private module Cached {
6565
instruction instanceof ChiInstruction // Chis always have modeled results
6666
}
6767

68+
cached
69+
predicate hasConflatedMemoryResult(Instruction instruction) {
70+
instruction instanceof UnmodeledDefinitionInstruction
71+
or
72+
instruction instanceof AliasedDefinitionInstruction
73+
or
74+
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
75+
or
76+
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
77+
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
78+
Alias::AliasedVirtualVariable
79+
or
80+
// If there is no memory location for a memory result, then it's unmodeled
81+
// and therefore conflated with every other unmodeled instruction.
82+
oldInstruction.hasMemoryResult() and
83+
not exists(Alias::getResultMemoryLocation(oldInstruction))
84+
)
85+
or
86+
exists(Alias::MemoryLocation location |
87+
instruction = Phi(_, location) and
88+
location.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
89+
)
90+
}
91+
6892
cached
6993
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
7094
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,34 @@ module InstructionSanity {
272272
func = switchInstr.getEnclosingIRFunction() and
273273
funcText = Language::getIdentityString(func.getFunction())
274274
}
275+
276+
/**
277+
* Holds if `instr` is on the chain of chi/phi instructions for all aliased
278+
* memory.
279+
*/
280+
private predicate isOnAliasedDefinitionChain(Instruction instr) {
281+
instr instanceof AliasedDefinitionInstruction
282+
or
283+
instr.getOpcode() instanceof Opcode::InitializeNonLocal
284+
or
285+
isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal())
286+
or
287+
isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
288+
}
289+
290+
private predicate shouldBeConflated(Instruction instr) {
291+
isOnAliasedDefinitionChain(instr)
292+
or
293+
instr instanceof UnmodeledDefinitionInstruction
294+
}
295+
296+
query predicate notMarkedAsConflated(Instruction instr) {
297+
shouldBeConflated(instr) and
298+
not instr.isResultConflated()
299+
}
300+
301+
query predicate wronglyMarkedAsConflated(Instruction instr) {
302+
instr.isResultConflated() and
303+
not shouldBeConflated(instr)
304+
}
275305
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ class Instruction extends Construction::TInstruction {
321321
Construction::hasModeledMemoryResult(this)
322322
}
323323

324+
/**
325+
* Holds if this is an instruction with a memory result that represents a
326+
* conflation of more than one object.
327+
*
328+
* This happens in practice when dereferencing a pointer that cannot be
329+
* tracked back to a single local allocation. Such memory is instead modeled
330+
* as originating on the `AliasedDefinitionInstruction` at the entry of the
331+
* function.
332+
*/
333+
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
334+
324335
/**
325336
* Gets the successor of this instruction along the control flow edge
326337
* specified by `kind`.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ private module Cached {
6161
cached
6262
predicate hasModeledMemoryResult(Instruction instruction) { none() }
6363

64+
cached
65+
predicate hasConflatedMemoryResult(Instruction instruction) {
66+
instruction instanceof UnmodeledDefinitionInstruction
67+
or
68+
instruction instanceof AliasedDefinitionInstruction
69+
or
70+
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
71+
}
72+
6473
cached
6574
Expr getInstructionConvertedResultExpression(Instruction instruction) {
6675
exists(TranslatedExpr translatedExpr |

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,34 @@ module InstructionSanity {
272272
func = switchInstr.getEnclosingIRFunction() and
273273
funcText = Language::getIdentityString(func.getFunction())
274274
}
275+
276+
/**
277+
* Holds if `instr` is on the chain of chi/phi instructions for all aliased
278+
* memory.
279+
*/
280+
private predicate isOnAliasedDefinitionChain(Instruction instr) {
281+
instr instanceof AliasedDefinitionInstruction
282+
or
283+
instr.getOpcode() instanceof Opcode::InitializeNonLocal
284+
or
285+
isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal())
286+
or
287+
isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
288+
}
289+
290+
private predicate shouldBeConflated(Instruction instr) {
291+
isOnAliasedDefinitionChain(instr)
292+
or
293+
instr instanceof UnmodeledDefinitionInstruction
294+
}
295+
296+
query predicate notMarkedAsConflated(Instruction instr) {
297+
shouldBeConflated(instr) and
298+
not instr.isResultConflated()
299+
}
300+
301+
query predicate wronglyMarkedAsConflated(Instruction instr) {
302+
instr.isResultConflated() and
303+
not shouldBeConflated(instr)
304+
}
275305
}

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ class Instruction extends Construction::TInstruction {
321321
Construction::hasModeledMemoryResult(this)
322322
}
323323

324+
/**
325+
* Holds if this is an instruction with a memory result that represents a
326+
* conflation of more than one object.
327+
*
328+
* This happens in practice when dereferencing a pointer that cannot be
329+
* tracked back to a single local allocation. Such memory is instead modeled
330+
* as originating on the `AliasedDefinitionInstruction` at the entry of the
331+
* function.
332+
*/
333+
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
334+
324335
/**
325336
* Gets the successor of this instruction along the control flow edge
326337
* specified by `kind`.

0 commit comments

Comments
 (0)