mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #4142 from MathiasVP/mathiasvp/read-step-without-memory-operands
C++: Use IR alias analysis for field flow
This commit is contained in:
@@ -144,8 +144,23 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) { none() }
|
||||
|
||||
/**
|
||||
* Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
|
||||
*/
|
||||
private Field getAField(Class c, int startBit, int endBit) {
|
||||
result.getDeclaringType() = c and
|
||||
startBit = 8 * result.getByteOffset() and
|
||||
endBit = 8 * result.getType().getSize() + startBit
|
||||
or
|
||||
exists(Field f, Class cInner |
|
||||
f = c.getAField() and
|
||||
cInner = f.getUnderlyingType() and
|
||||
result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TContent =
|
||||
TFieldContent(Field f) or
|
||||
TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
|
||||
TCollectionContent() or
|
||||
TArrayContent()
|
||||
|
||||
@@ -163,17 +178,18 @@ class Content extends TContent {
|
||||
}
|
||||
|
||||
private class FieldContent extends Content, TFieldContent {
|
||||
Field f;
|
||||
Class c;
|
||||
int startBit;
|
||||
int endBit;
|
||||
|
||||
FieldContent() { this = TFieldContent(f) }
|
||||
FieldContent() { this = TFieldContent(c, startBit, endBit) }
|
||||
|
||||
Field getField() { result = f }
|
||||
// Ensure that there's just 1 result for `toString`.
|
||||
override string toString() { result = min(Field f | f = getAField() | f.toString()) }
|
||||
|
||||
override string toString() { result = f.toString() }
|
||||
predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
|
||||
|
||||
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
Field getAField() { result = getAField(c, startBit, endBit) }
|
||||
}
|
||||
|
||||
private class CollectionContent extends Content, TCollectionContent {
|
||||
@@ -185,20 +201,38 @@ private class ArrayContent extends Content, TArrayContent {
|
||||
}
|
||||
|
||||
private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) {
|
||||
exists(FieldAddressInstruction fa, StoreInstruction store |
|
||||
exists(StoreInstruction store, Class c |
|
||||
store = node2.asInstruction() and
|
||||
store.getDestinationAddress() = fa and
|
||||
store.getSourceValue() = node1.asInstruction() and
|
||||
f.(FieldContent).getField() = fa.getField()
|
||||
getWrittenField(store, f.(FieldContent).getAField(), c) and
|
||||
f.(FieldContent).hasOffset(c, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate getWrittenField(StoreInstruction store, Field f, Class c) {
|
||||
exists(FieldAddressInstruction fa |
|
||||
fa = store.getDestinationAddress() and
|
||||
f = fa.getField() and
|
||||
c = f.getDeclaringType()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) {
|
||||
exists(FieldAddressInstruction fa, StoreInstruction store |
|
||||
exists(StoreInstruction store, ChiInstruction chi |
|
||||
node1.asInstruction() = store and
|
||||
store.getDestinationAddress() = fa and
|
||||
node2.asInstruction().(ChiInstruction).getPartial() = store and
|
||||
f.(FieldContent).getField() = fa.getField()
|
||||
node2.asInstruction() = chi and
|
||||
chi.getPartial() = store and
|
||||
exists(Class c |
|
||||
c = chi.getResultType() and
|
||||
exists(int startBit, int endBit |
|
||||
chi.getUpdatedInterval(startBit, endBit) and
|
||||
f.(FieldContent).hasOffset(c, startBit, endBit)
|
||||
)
|
||||
or
|
||||
getWrittenField(store, f.(FieldContent).getAField(), c) and
|
||||
f.(FieldContent).hasOffset(c, _, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -212,17 +246,37 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
storeStepChi(node1, f, node2)
|
||||
}
|
||||
|
||||
bindingset[result, i]
|
||||
private int unbindInt(int i) { i <= result and i >= result }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
|
||||
exists(FieldAddressInstruction fa |
|
||||
fa = load.getSourceAddress() and
|
||||
f = fa.getField() and
|
||||
c = f.getDeclaringType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, Content f, Node node2) {
|
||||
exists(FieldAddressInstruction fa, LoadInstruction load |
|
||||
load.getSourceAddress() = fa and
|
||||
exists(LoadInstruction load |
|
||||
node2.asInstruction() = load and
|
||||
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
|
||||
fa.getField() = f.(FieldContent).getField() and
|
||||
load = node2.asInstruction()
|
||||
exists(Class c |
|
||||
c = load.getSourceValueOperand().getAnyDef().getResultType() and
|
||||
exists(int startBit, int endBit |
|
||||
load.getSourceValueOperand().getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and
|
||||
f.(FieldContent).hasOffset(c, startBit, endBit)
|
||||
)
|
||||
or
|
||||
getLoadedField(load, f.(FieldContent).getAField(), c) and
|
||||
f.(FieldContent).hasOffset(c, _, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -335,12 +335,14 @@ abstract private class PartialDefinitionNode extends PostUpdateNode {
|
||||
|
||||
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override ChiInstruction instr;
|
||||
FieldAddressInstruction field;
|
||||
StoreInstruction store;
|
||||
|
||||
ExplicitFieldStoreQualifierNode() {
|
||||
not instr.isResultConflated() and
|
||||
exists(StoreInstruction store |
|
||||
instr.getPartial() = store and field = store.getDestinationAddress()
|
||||
instr.getPartial() = store and
|
||||
(
|
||||
instr.getUpdatedInterval(_, _) or
|
||||
store.getDestinationAddress() instanceof FieldAddressInstruction
|
||||
)
|
||||
}
|
||||
|
||||
@@ -351,7 +353,12 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
result = field.getObjectAddress().getUnconvertedResultExpression()
|
||||
result =
|
||||
store
|
||||
.getDestinationAddress()
|
||||
.(FieldAddressInstruction)
|
||||
.getObjectAddress()
|
||||
.getUnconvertedResultExpression()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,17 +370,22 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
*/
|
||||
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override StoreInstruction instr;
|
||||
FieldAddressInstruction field;
|
||||
|
||||
ExplicitSingleFieldStoreQualifierNode() {
|
||||
field = instr.getDestinationAddress() and
|
||||
not exists(ChiInstruction chi | chi.getPartial() = instr)
|
||||
not exists(ChiInstruction chi | chi.getPartial() = instr) and
|
||||
// Without this condition any store would create a `PostUpdateNode`.
|
||||
instr.getDestinationAddress() instanceof FieldAddressInstruction
|
||||
}
|
||||
|
||||
override Node getPreUpdateNode() { none() }
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
result = field.getObjectAddress().getUnconvertedResultExpression()
|
||||
result =
|
||||
instr
|
||||
.getDestinationAddress()
|
||||
.(FieldAddressInstruction)
|
||||
.getObjectAddress()
|
||||
.getUnconvertedResultExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
|
||||
* Gets the operand that represents the new value written by the memory write.
|
||||
*/
|
||||
final Instruction getPartial() { result = getPartialOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
|
||||
*/
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
|
||||
*/
|
||||
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
|
||||
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -617,3 +617,9 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(VariableMemoryLocation location) { result = location.getStartBitOffset() }
|
||||
|
||||
/** Gets the end bit offset of a `MemoryLocation`, if any. */
|
||||
int getEndBitOffset(VariableMemoryLocation location) { result = location.getEndBitOffset() }
|
||||
|
||||
@@ -149,6 +149,34 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the partial operand of this `ChiInstruction` updates the bit range
|
||||
* `[startBitOffset, endBitOffset)` of the total operand.
|
||||
*/
|
||||
cached
|
||||
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(chi.getPartial()) and
|
||||
location = Alias::getResultMemoryLocation(oldInstruction) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` totally overlaps with its definition and consumes the bit range
|
||||
* `[startBitOffset, endBitOffset)`.
|
||||
*/
|
||||
cached
|
||||
predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand |
|
||||
oldOperand = operand.getUse().(OldInstruction).getAnOperand() and
|
||||
location = Alias::getOperandMemoryLocation(oldOperand) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
|
||||
* Gets the operand that represents the new value written by the memory write.
|
||||
*/
|
||||
final Instruction getPartial() { result = getPartialOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
|
||||
*/
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
|
||||
*/
|
||||
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
|
||||
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -182,6 +182,18 @@ Instruction getMemoryOperandDefinition(
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the partial operand of this `ChiInstruction` updates the bit range
|
||||
* `[startBitOffset, endBitOffset)` of the total operand.
|
||||
*/
|
||||
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)`.
|
||||
*/
|
||||
predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() }
|
||||
|
||||
/** Gets a non-phi instruction that defines an operand of `instr`. */
|
||||
private Instruction getNonPhiOperandDef(Instruction instr) {
|
||||
result = getRegisterOperandDefinition(instr, _)
|
||||
|
||||
@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
|
||||
* Gets the operand that represents the new value written by the memory write.
|
||||
*/
|
||||
final Instruction getPartial() { result = getPartialOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
|
||||
*/
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
|
||||
*/
|
||||
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
|
||||
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -149,6 +149,34 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the partial operand of this `ChiInstruction` updates the bit range
|
||||
* `[startBitOffset, endBitOffset)` of the total operand.
|
||||
*/
|
||||
cached
|
||||
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(chi.getPartial()) and
|
||||
location = Alias::getResultMemoryLocation(oldInstruction) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` totally overlaps with its definition and consumes the bit range
|
||||
* `[startBitOffset, endBitOffset)`.
|
||||
*/
|
||||
cached
|
||||
predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand |
|
||||
oldOperand = operand.getUse().(OldInstruction).getAnOperand() and
|
||||
location = Alias::getOperandMemoryLocation(oldOperand) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -79,3 +79,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
result = getMemoryLocation(getAddressOperandAllocation(operand.getAddressOperand()))
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(MemoryLocation location) { none() }
|
||||
|
||||
/** Gets the end bit offset of a `MemoryLocation`, if any. */
|
||||
int getEndBitOffset(MemoryLocation location) { none() }
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
{
|
||||
if (C1 *c1 = dynamic_cast<C1 *>(c))
|
||||
{
|
||||
sink(c1->a); // $ast $ir
|
||||
sink(c1->a); // $ast,ir
|
||||
}
|
||||
C *cc;
|
||||
if (C2 *c2 = dynamic_cast<C2 *>(c))
|
||||
|
||||
@@ -92,3 +92,12 @@ void nestedAssign() {
|
||||
w.s.m1 = user_input();
|
||||
sink(w.s.m1); // $ast,ir
|
||||
}
|
||||
|
||||
void addressOfField() {
|
||||
S s;
|
||||
s.m1 = user_input();
|
||||
|
||||
S s_copy = s;
|
||||
int* px = &s_copy.m1;
|
||||
sink(*px); // $f-:ast $ir
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | IR only |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | IR only |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | IR only |
|
||||
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:102:8:102:10 | * ... | IR only |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | AST only |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | AST only |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | AST only |
|
||||
|
||||
@@ -60,6 +60,10 @@ edges
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
|
||||
| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] |
|
||||
| aliasing.cpp:98:3:98:21 | Store | aliasing.cpp:98:3:98:21 | Chi [m1] |
|
||||
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Store |
|
||||
| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... |
|
||||
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] |
|
||||
| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
|
||||
@@ -247,6 +251,11 @@ nodes
|
||||
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:98:3:98:21 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:98:3:98:21 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] |
|
||||
| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... |
|
||||
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] |
|
||||
@@ -385,6 +394,7 @@ nodes
|
||||
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:102:8:102:10 | * ... | aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:102:8:102:10 | * ... | * ... flows from $@ | aliasing.cpp:98:10:98:19 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input |
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
| aliasing.cpp:86:5:86:6 | m1 | AST only |
|
||||
| aliasing.cpp:92:3:92:3 | w | AST only |
|
||||
| aliasing.cpp:92:7:92:8 | m1 | AST only |
|
||||
| aliasing.cpp:98:5:98:6 | m1 | AST only |
|
||||
| by_reference.cpp:12:8:12:8 | a | AST only |
|
||||
| by_reference.cpp:16:11:16:11 | a | AST only |
|
||||
| by_reference.cpp:20:5:20:8 | this | AST only |
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
| aliasing.cpp:79:3:79:3 | s |
|
||||
| aliasing.cpp:86:3:86:3 | s |
|
||||
| aliasing.cpp:92:5:92:5 | s |
|
||||
| aliasing.cpp:98:3:98:3 | s |
|
||||
| by_reference.cpp:12:5:12:5 | s |
|
||||
| by_reference.cpp:16:5:16:8 | this |
|
||||
| by_reference.cpp:84:3:84:7 | inner |
|
||||
|
||||
@@ -185,6 +185,8 @@
|
||||
| aliasing.cpp:92:3:92:3 | w |
|
||||
| aliasing.cpp:92:5:92:5 | s |
|
||||
| aliasing.cpp:92:7:92:8 | m1 |
|
||||
| aliasing.cpp:98:3:98:3 | s |
|
||||
| aliasing.cpp:98:5:98:6 | m1 |
|
||||
| by_reference.cpp:12:5:12:5 | s |
|
||||
| by_reference.cpp:12:8:12:8 | a |
|
||||
| by_reference.cpp:16:5:16:8 | this |
|
||||
|
||||
@@ -258,7 +258,7 @@ void test_lambdas()
|
||||
c = source();
|
||||
};
|
||||
e(t, u, w);
|
||||
sink(w); // tainted
|
||||
sink(w); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
// --- taint through return value ---
|
||||
@@ -348,8 +348,8 @@ void test_outparams()
|
||||
myNotAssign(e, t);
|
||||
|
||||
sink(t); // tainted
|
||||
sink(a); // tainted
|
||||
sink(b); // tainted
|
||||
sink(a); // tainted [NOT DETECTED by IR]
|
||||
sink(b); // tainted [NOT DETECTED by IR]
|
||||
sink(c); // tainted [NOT DETECTED]
|
||||
sink(d); // tainted [NOT DETECTED]
|
||||
sink(e);
|
||||
@@ -468,7 +468,7 @@ void test_swop() {
|
||||
swop(x, y);
|
||||
|
||||
sink(x); // clean [FALSE POSITIVE]
|
||||
sink(y); // tainted
|
||||
sink(y); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
// --- getdelim ---
|
||||
|
||||
@@ -16,13 +16,8 @@
|
||||
| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:145:7:145:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only |
|
||||
| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
| copyableclass.cpp:43:8:43:9 | copyableclass.cpp:38:8:38:13 | AST only |
|
||||
| copyableclass.cpp:65:8:65:9 | copyableclass.cpp:60:40:60:45 | AST only |
|
||||
| copyableclass.cpp:66:8:66:9 | copyableclass.cpp:63:24:63:29 | AST only |
|
||||
| copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only |
|
||||
| copyableclass.cpp:67:11:67:21 | copyableclass.cpp:67:13:67:18 | IR only |
|
||||
| copyableclass_declonly.cpp:40:8:40:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only |
|
||||
| copyableclass_declonly.cpp:41:8:41:9 | copyableclass_declonly.cpp:35:32:35:37 | AST only |
|
||||
| copyableclass_declonly.cpp:42:8:42:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only |
|
||||
@@ -41,13 +36,8 @@
|
||||
| format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only |
|
||||
| format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only |
|
||||
| format.cpp:115:8:115:13 | format.cpp:114:37:114:50 | AST only |
|
||||
| movableclass.cpp:44:8:44:9 | movableclass.cpp:39:21:39:26 | AST only |
|
||||
| movableclass.cpp:45:8:45:9 | movableclass.cpp:40:23:40:28 | AST only |
|
||||
| movableclass.cpp:46:8:46:9 | movableclass.cpp:42:8:42:13 | AST only |
|
||||
| movableclass.cpp:54:8:54:9 | movableclass.cpp:50:38:50:43 | AST only |
|
||||
| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only |
|
||||
| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only |
|
||||
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
|
||||
| movableclass.cpp:65:11:65:21 | movableclass.cpp:65:13:65:18 | IR only |
|
||||
| smart_pointer.cpp:12:10:12:10 | smart_pointer.cpp:11:52:11:57 | AST only |
|
||||
| smart_pointer.cpp:13:10:13:10 | smart_pointer.cpp:11:52:11:57 | AST only |
|
||||
| smart_pointer.cpp:24:10:24:10 | smart_pointer.cpp:23:52:23:57 | AST only |
|
||||
@@ -191,10 +181,6 @@
|
||||
| stringstream.cpp:143:11:143:11 | stringstream.cpp:143:14:143:21 | IR only |
|
||||
| stringstream.cpp:143:11:143:22 | stringstream.cpp:143:14:143:19 | IR only |
|
||||
| stringstream.cpp:143:11:143:22 | stringstream.cpp:143:14:143:21 | IR only |
|
||||
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
|
||||
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
| structlikeclass.cpp:60:8:60:9 | structlikeclass.cpp:55:40:55:45 | AST only |
|
||||
| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only |
|
||||
| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | AST only |
|
||||
| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only |
|
||||
|
||||
@@ -17,9 +17,23 @@
|
||||
| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source |
|
||||
| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
| copyableclass.cpp:43:8:43:9 | s4 | copyableclass.cpp:38:8:38:13 | call to source |
|
||||
| copyableclass.cpp:65:8:65:9 | s1 | copyableclass.cpp:60:40:60:45 | call to source |
|
||||
| copyableclass.cpp:66:8:66:9 | s2 | copyableclass.cpp:63:24:63:29 | call to source |
|
||||
| copyableclass.cpp:67:11:67:21 | (reference dereference) | copyableclass.cpp:67:13:67:18 | call to source |
|
||||
| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
|
||||
| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source |
|
||||
| movableclass.cpp:45:8:45:9 | s2 | movableclass.cpp:40:23:40:28 | call to source |
|
||||
| movableclass.cpp:46:8:46:9 | s3 | movableclass.cpp:42:8:42:13 | call to source |
|
||||
| movableclass.cpp:54:8:54:9 | s1 | movableclass.cpp:50:38:50:43 | call to source |
|
||||
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
|
||||
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
|
||||
| movableclass.cpp:65:11:65:21 | (reference dereference) | movableclass.cpp:65:13:65:18 | call to source |
|
||||
| string.cpp:28:7:28:7 | (const char *)... | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:24 | call to source |
|
||||
@@ -56,7 +70,11 @@
|
||||
| stringstream.cpp:143:11:143:22 | (reference dereference) | stringstream.cpp:143:14:143:21 | (const char *)... |
|
||||
| stringstream.cpp:143:11:143:22 | (reference to) | stringstream.cpp:143:14:143:19 | call to source |
|
||||
| stringstream.cpp:143:11:143:22 | (reference to) | stringstream.cpp:143:14:143:21 | (const char *)... |
|
||||
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
|
||||
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source |
|
||||
| structlikeclass.cpp:60:8:60:9 | s1 | structlikeclass.cpp:55:40:55:45 | call to source |
|
||||
| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source |
|
||||
| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source |
|
||||
| swap1.cpp:73:12:73:16 | data1 | swap1.cpp:71:15:71:20 | call to source |
|
||||
|
||||
@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
|
||||
* Gets the operand that represents the new value written by the memory write.
|
||||
*/
|
||||
final Instruction getPartial() { result = getPartialOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
|
||||
*/
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
|
||||
*/
|
||||
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
|
||||
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,6 +214,20 @@ private module Cached {
|
||||
result = getMemoryOperandDefinition(instr, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the partial operand of this `ChiInstruction` updates the bit range
|
||||
* `[startBitOffset, endBitOffset)` of the total operand.
|
||||
*/
|
||||
cached
|
||||
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)`.
|
||||
*/
|
||||
cached
|
||||
predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
|
||||
* Gets the operand that represents the new value written by the memory write.
|
||||
*/
|
||||
final Instruction getPartial() { result = getPartialOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
|
||||
*/
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
|
||||
*/
|
||||
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
|
||||
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -149,6 +149,34 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the partial operand of this `ChiInstruction` updates the bit range
|
||||
* `[startBitOffset, endBitOffset)` of the total operand.
|
||||
*/
|
||||
cached
|
||||
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(chi.getPartial()) and
|
||||
location = Alias::getResultMemoryLocation(oldInstruction) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` totally overlaps with its definition and consumes the bit range
|
||||
* `[startBitOffset, endBitOffset)`.
|
||||
*/
|
||||
cached
|
||||
predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand |
|
||||
oldOperand = operand.getUse().(OldInstruction).getAnOperand() and
|
||||
location = Alias::getOperandMemoryLocation(oldOperand) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -79,3 +79,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
result = getMemoryLocation(getAddressOperandAllocation(operand.getAddressOperand()))
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(MemoryLocation location) { none() }
|
||||
|
||||
/** Gets the end bit offset of a `MemoryLocation`, if any. */
|
||||
int getEndBitOffset(MemoryLocation location) { none() }
|
||||
|
||||
Reference in New Issue
Block a user