C++: Update AliasedSSA to use Allocation instead of IRVariable

This introduces a new type of `MemoryLocation`: `EntireAllocationMemoryLocation`, representing an entire contiguous allocation whose size is not known. This is used to model the memory accesses on `InitializeIndirection` and `ReturnIndirection`.
This commit is contained in:
Dave Bartolomeo
2020-01-28 10:55:24 -07:00
parent 165a45d9b5
commit 976b564b68

View File

@@ -6,38 +6,52 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import AliasConfiguration
private class IntValue = Ints::IntValue;
private predicate isIndirectOrBufferMemoryAccess(MemoryAccessKind kind) {
kind instanceof IndirectMemoryAccess or
kind instanceof BufferMemoryAccess
}
private predicate hasResultMemoryAccess(
Instruction instr, IRVariable var, IRType type, Language::LanguageType languageType,
Instruction instr, Allocation var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
) {
resultPointsTo(instr.getResultAddress(), var, startBitOffset) and
languageType = instr.getResultLanguageType() and
type = languageType.getIRType() and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
exists(AddressOperand addrOperand |
addrOperand = instr.getResultAddressOperand() and
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
languageType = instr.getResultLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
)
}
private predicate hasOperandMemoryAccess(
MemoryOperand operand, IRVariable var, IRType type, Language::LanguageType languageType,
MemoryOperand operand, Allocation var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
) {
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
exists(AddressOperand addrOperand |
addrOperand = operand.getAddressOperand() and
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
)
}
private newtype TMemoryLocation =
TVariableMemoryLocation(
IRVariable var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
Allocation var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
IntValue endBitOffset, boolean isMayAccess
) {
(
@@ -45,17 +59,18 @@ private newtype TMemoryLocation =
or
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or
exists(IRAutomaticVariable autoVar |
// Always create a memory location for the entire variable.
autoVar = var and
type = autoVar.getIRType() and
startBitOffset = 0 and
endBitOffset = type.getByteSize() * 8 and
isMayAccess = false
)
// For a stack variable, always create a memory location for the entire variable.
var.isAlwaysAllocatedOnStack() and
type = var.getIRType() and
startBitOffset = 0 and
endBitOffset = type.getByteSize() * 8 and
isMayAccess = false
) and
languageType = type.getCanonicalLanguageType()
} or
TEntireAllocationMemoryLocation(IndirectParameterAllocation var, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
@@ -94,6 +109,8 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract predicate isMayAccess();
Allocation getAllocation() { none() }
/**
* Holds if the location cannot be overwritten except by definition of a `MemoryLocation` for
* which `def.canDefineReadOnly()` holds.
@@ -114,26 +131,63 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract class VirtualVariable extends MemoryLocation { }
abstract class AllocationMemoryLocation extends MemoryLocation {
Allocation var;
boolean isMayAccess;
AllocationMemoryLocation() {
this instanceof TMemoryLocation and
isMayAccess = false
or
isMayAccess = true // Just ensures that `isMayAccess` is bound.
}
final override VirtualVariable getVirtualVariable() {
if allocationEscapes(var)
then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false)
else result.(AllocationMemoryLocation).getAllocation() = var
}
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final override Location getLocation() { result = var.getLocation() }
final override Allocation getAllocation() { result = var }
final override predicate isMayAccess() { isMayAccess = true }
final override predicate isReadOnly() { var.isReadOnly() }
}
/**
* An access to memory within a single known `IRVariable`. The variable may be either an unescaped variable
* (with its own `VirtualIRVariable`) or an escaped variable (assigned to `UnknownVirtualVariable`).
*/
class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
IRVariable var;
class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLocation {
IRType type;
Language::LanguageType languageType;
IntValue startBitOffset;
IntValue endBitOffset;
boolean isMayAccess;
VariableMemoryLocation() {
this = TVariableMemoryLocation(var, type, languageType, startBitOffset, endBitOffset,
isMayAccess)
}
private string getIntervalString() {
if coversEntireVariable()
then result = ""
else result = Interval::getIntervalString(startBitOffset, endBitOffset)
}
private string getTypeString() {
if coversEntireVariable() and type = var.getIRType()
then result = ""
else result = "<" + languageType.toString() + ">"
}
final override string toStringInternal() {
result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
type.toString() + ", " + languageType.toString() + ">"
result = var.toString() + getIntervalString() + getTypeString()
}
final override Language::LanguageType getType() {
@@ -151,34 +205,16 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
result = type.getCanonicalLanguageType()
}
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final override Location getLocation() { result = var.getLocation() }
final IntValue getStartBitOffset() { result = startBitOffset }
final IntValue getEndBitOffset() { result = endBitOffset }
final IRVariable getVariable() { result = var }
final override string getUniqueId() {
result = var.getUniqueId() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
type.getIdentityString() + ">"
}
final override VirtualVariable getVirtualVariable() {
if variableAddressEscapes(var)
then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false)
else
result = TVariableMemoryLocation(var, var.getIRType(), _, 0,
var.getIRType().getByteSize() * 8, false)
}
final override predicate isMayAccess() { isMayAccess = true }
final override predicate isReadOnly() { var.isReadOnly() }
final override predicate isAlwaysAllocatedOnStack() { var instanceof IRAutomaticVariable }
final override predicate isAlwaysAllocatedOnStack() { var.isAlwaysAllocatedOnStack() }
/**
* Holds if this memory location covers the entire variable.
@@ -189,6 +225,26 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
}
}
class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
AllocationMemoryLocation {
EntireAllocationMemoryLocation() { this = TEntireAllocationMemoryLocation(var, isMayAccess) }
final override string toStringInternal() { result = var.toString() }
final override Language::LanguageType getType() {
result = any(IRUnknownType unknownType).getCanonicalLanguageType()
}
final override string getUniqueId() { result = var.getUniqueId() }
}
class EntireAllocationVirtualVariable extends EntireAllocationMemoryLocation, VirtualVariable {
EntireAllocationVirtualVariable() {
not allocationEscapes(var) and
not isMayAccess()
}
}
/**
* Represents the `MemoryLocation` for an `IRVariable` that acts as its own `VirtualVariable`. Includes any
* `VariableMemoryLocation` that exactly overlaps its entire `IRVariable`, and only if that `IRVariable` does not
@@ -196,7 +252,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
*/
class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
VariableVirtualVariable() {
not variableAddressEscapes(var) and
not allocationEscapes(var) and
type = var.getIRType() and
coversEntireVariable() and
not isMayAccess()
@@ -354,13 +410,30 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
not use.isAlwaysAllocatedOnStack()
)
or
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof EntireAllocationMemoryLocation and
(
// EntireAllocationMemoryLocation exactly overlaps itself.
use instanceof EntireAllocationMemoryLocation and
result instanceof MustExactlyOverlap
or
// EntireAllocationMemoryLocation totally overlaps any location within the same virtual
// variable.
not use instanceof EntireAllocationMemoryLocation and
result instanceof MustTotallyOverlap
)
or
exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and
(
// A VariableMemoryLocation may partially overlap an unknown location within the same
// virtual variable.
def.getVirtualVariable() = use.getVirtualVariable() and
(use instanceof UnknownMemoryLocation or use instanceof AllAliasedMemory) and
(
use instanceof UnknownMemoryLocation or
use instanceof AllAliasedMemory or
use instanceof EntireAllocationMemoryLocation
) and
result instanceof MayPartiallyOverlap
or
// A VariableMemoryLocation that is not a local variable may partially overlap an
@@ -421,19 +494,19 @@ private predicate isRelatableMemoryLocation(VariableMemoryLocation vml) {
vml.getStartBitOffset() != Ints::unknown()
}
private predicate isCoveredOffset(IRVariable var, int offsetRank, VariableMemoryLocation vml) {
private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemoryLocation vml) {
exists(int startRank, int endRank, VirtualVariable vvar |
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
vml.getEndBitOffset() = rank[endRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
var = vml.getVariable() and
var = vml.getAllocation() and
vvar = vml.getVirtualVariable() and
isRelatableMemoryLocation(vml) and
offsetRank in [startRank .. endRank]
)
}
private predicate hasUnknownOffset(IRVariable var, VariableMemoryLocation vml) {
vml.getVariable() = var and
private predicate hasUnknownOffset(Allocation var, VariableMemoryLocation vml) {
vml.getAllocation() = var and
(
vml.getStartBitOffset() = Ints::unknown() or
vml.getEndBitOffset() = Ints::unknown()
@@ -443,14 +516,14 @@ private predicate hasUnknownOffset(IRVariable var, VariableMemoryLocation vml) {
private predicate overlappingIRVariableMemoryLocations(
VariableMemoryLocation def, VariableMemoryLocation use
) {
exists(IRVariable var, int offsetRank |
exists(Allocation var, int offsetRank |
isCoveredOffset(var, offsetRank, def) and
isCoveredOffset(var, offsetRank, use)
)
or
hasUnknownOffset(use.getVariable(), def)
hasUnknownOffset(use.getAllocation(), def)
or
hasUnknownOffset(def.getVariable(), use)
hasUnknownOffset(def.getAllocation(), use)
}
private Overlap getVariableMemoryLocationOverlap(
@@ -467,16 +540,20 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(
(
kind.usesAddressOperand() and
isIndirectOrBufferMemoryAccess(kind) and
if hasResultMemoryAccess(instr, _, _, _, _, _, _)
then
exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
)
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction(), isMayAccess)
)
or
kind instanceof EntireAllocationMemoryAccess and
result = TEntireAllocationMemoryLocation(getAddressOperandAllocation(instr
.getResultAddressOperand()), isMayAccess)
or
kind instanceof EscapedMemoryAccess and
result = TAllAliasedMemory(instr.getEnclosingIRFunction(), isMayAccess)
or
@@ -492,16 +569,20 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(
(
kind.usesAddressOperand() and
isIndirectOrBufferMemoryAccess(kind) and
if hasOperandMemoryAccess(operand, _, _, _, _, _, _)
then
exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
)
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
)
or
kind instanceof EntireAllocationMemoryAccess and
result = TEntireAllocationMemoryLocation(getAddressOperandAllocation(operand
.getAddressOperand()), isMayAccess)
or
kind instanceof EscapedMemoryAccess and
result = TAllAliasedMemory(operand.getEnclosingIRFunction(), isMayAccess)
or