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.
This commit is contained in:
Jonas Jensen
2020-03-20 17:57:18 +01:00
parent 67cb8525bf
commit f6f9afe462
26 changed files with 314 additions and 14 deletions

View File

@@ -183,7 +183,7 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
i2.(UnaryInstruction).getUnary() = i1
or
i2.(ChiInstruction).getPartial() = i1 and
not isChiForAllAliasedMemory(i2)
not i2.isResultConflated()
or
exists(BinaryInstruction bin |
bin = i2 and
@@ -276,19 +276,6 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
)
}
/**
* Holds if `chi` is on the chain of chi-instructions for all aliased memory.
* Taint should not pass through these instructions since they tend to mix up
* unrelated objects.
*/
private predicate isChiForAllAliasedMemory(Instruction instr) {
instr.(ChiInstruction).getTotal() instanceof AliasedDefinitionInstruction
or
isChiForAllAliasedMemory(instr.(ChiInstruction).getTotal())
or
isChiForAllAliasedMemory(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
}
private predicate modelTaintToReturnValue(Function f, int parameterIn) {
// Taint flow from parameter to return value
exists(FunctionInput modelIn, FunctionOutput modelOut |

View File

@@ -272,4 +272,34 @@ module InstructionSanity {
func = switchInstr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if `instr` is on the chain of chi/phi instructions for all aliased
* memory.
*/
private predicate isOnAliasedDefinitionChain(Instruction instr) {
instr instanceof AliasedDefinitionInstruction
or
instr.getOpcode() instanceof Opcode::InitializeNonLocal
or
isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal())
or
isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
}
private predicate shouldBeConflated(Instruction instr) {
isOnAliasedDefinitionChain(instr)
or
instr instanceof UnmodeledDefinitionInstruction
}
query predicate notMarkedAsConflated(Instruction instr) {
shouldBeConflated(instr) and
not instr.isResultConflated()
}
query predicate wronglyMarkedAsConflated(Instruction instr) {
instr.isResultConflated() and
not shouldBeConflated(instr)
}
}

View File

@@ -321,6 +321,17 @@ class Instruction extends Construction::TInstruction {
Construction::hasModeledMemoryResult(this)
}
/**
* Holds if this is an instruction with a memory result that represents a
* conflation of more than one object.
*
* This happens in practice when dereferencing a pointer that cannot be
* tracked back to a single local allocation. Such memory is instead modeled
* as originating on the `AliasedDefinitionInstruction` at the entry of the
* function.
*/
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
/**
* Gets the successor of this instruction along the control flow edge
* specified by `kind`.

View File

@@ -354,6 +354,7 @@ class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
final override predicate isMayAccess() { isMayAccess = true }
}
/** A virtual variable that groups all escaped memory within a function. */
class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
AliasedVirtualVariable() { not isMayAccess() }
}

View File

@@ -65,6 +65,30 @@ private module Cached {
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof UnmodeledDefinitionInstruction
or
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
or
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
or
// If there is no memory location for a memory result, then it's unmodeled
// and therefore conflated with every other unmodeled instruction.
oldInstruction.hasMemoryResult() and
not exists(Alias::getResultMemoryLocation(oldInstruction))
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
location.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
)
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |

View File

@@ -272,4 +272,34 @@ module InstructionSanity {
func = switchInstr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if `instr` is on the chain of chi/phi instructions for all aliased
* memory.
*/
private predicate isOnAliasedDefinitionChain(Instruction instr) {
instr instanceof AliasedDefinitionInstruction
or
instr.getOpcode() instanceof Opcode::InitializeNonLocal
or
isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal())
or
isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
}
private predicate shouldBeConflated(Instruction instr) {
isOnAliasedDefinitionChain(instr)
or
instr instanceof UnmodeledDefinitionInstruction
}
query predicate notMarkedAsConflated(Instruction instr) {
shouldBeConflated(instr) and
not instr.isResultConflated()
}
query predicate wronglyMarkedAsConflated(Instruction instr) {
instr.isResultConflated() and
not shouldBeConflated(instr)
}
}

View File

@@ -321,6 +321,17 @@ class Instruction extends Construction::TInstruction {
Construction::hasModeledMemoryResult(this)
}
/**
* Holds if this is an instruction with a memory result that represents a
* conflation of more than one object.
*
* This happens in practice when dereferencing a pointer that cannot be
* tracked back to a single local allocation. Such memory is instead modeled
* as originating on the `AliasedDefinitionInstruction` at the entry of the
* function.
*/
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
/**
* Gets the successor of this instruction along the control flow edge
* specified by `kind`.

View File

@@ -61,6 +61,15 @@ private module Cached {
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof UnmodeledDefinitionInstruction
or
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |

View File

@@ -272,4 +272,34 @@ module InstructionSanity {
func = switchInstr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if `instr` is on the chain of chi/phi instructions for all aliased
* memory.
*/
private predicate isOnAliasedDefinitionChain(Instruction instr) {
instr instanceof AliasedDefinitionInstruction
or
instr.getOpcode() instanceof Opcode::InitializeNonLocal
or
isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal())
or
isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
}
private predicate shouldBeConflated(Instruction instr) {
isOnAliasedDefinitionChain(instr)
or
instr instanceof UnmodeledDefinitionInstruction
}
query predicate notMarkedAsConflated(Instruction instr) {
shouldBeConflated(instr) and
not instr.isResultConflated()
}
query predicate wronglyMarkedAsConflated(Instruction instr) {
instr.isResultConflated() and
not shouldBeConflated(instr)
}
}

View File

@@ -321,6 +321,17 @@ class Instruction extends Construction::TInstruction {
Construction::hasModeledMemoryResult(this)
}
/**
* Holds if this is an instruction with a memory result that represents a
* conflation of more than one object.
*
* This happens in practice when dereferencing a pointer that cannot be
* tracked back to a single local allocation. Such memory is instead modeled
* as originating on the `AliasedDefinitionInstruction` at the entry of the
* function.
*/
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
/**
* Gets the successor of this instruction along the control flow edge
* specified by `kind`.

View File

@@ -65,6 +65,30 @@ private module Cached {
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof UnmodeledDefinitionInstruction
or
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
or
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
or
// If there is no memory location for a memory result, then it's unmodeled
// and therefore conflated with every other unmodeled instruction.
oldInstruction.hasMemoryResult() and
not exists(Alias::getResultMemoryLocation(oldInstruction))
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
location.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
)
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |

View File

@@ -61,6 +61,11 @@ class MemoryLocation extends TMemoryLocation {
class VirtualVariable extends MemoryLocation { }
/** A virtual variable that groups all escaped memory within a function. */
class AliasedVirtualVariable extends VirtualVariable {
AliasedVirtualVariable() { none() }
}
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
def = use and result instanceof MustExactlyOverlap
or

View File

@@ -20,6 +20,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -20,6 +20,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -20,6 +20,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -16,6 +16,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -16,6 +16,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -568,6 +568,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -631,6 +631,8 @@ useNotDominatedByDefinition
| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) |
| vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | IR: main | int main(int, char**) |
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -577,6 +577,8 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType