Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -362,15 +362,22 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {

/**
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
* For instance, an update to a field of a struct containing only one field. For these cases we
* attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case
* (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`.
* For instance, an update to a field of a struct containing only one field. Even if the store does
* have a chi instruction, a subsequent use of the result of the store may be linked directly to the
* result of the store as an inexact definition if the store totally overlaps the use. For these
* cases we attach the PostUpdateNode to the store instruction. There's no obvious pre update node
* for this case (as the entire memory is updated), so `getPreUpdateNode` is implemented as
* `none()`.
*/
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
override StoreInstruction instr;

ExplicitSingleFieldStoreQualifierNode() {
not exists(ChiInstruction chi | chi.getPartial() = instr) and
(
instr.getAUse().isDefinitionInexact()
or
not exists(ChiInstruction chi | chi.getPartial() = instr)
) and
// Without this condition any store would create a `PostUpdateNode`.
instr.getDestinationAddress() instanceof FieldAddressInstruction
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,7 @@ private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil

/**
* Gets a short ID for an IR dataflow node.
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
* instruction and a dot (e.g. `m128.left`).
* - For `Variable`s, this is the qualified name of the variable.
*/
private string nodeId(DataFlow::Node node, int order1, int order2) {
exists(Instruction instruction | instruction = node.asInstruction() |
result = instruction.getResultId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
exists(Operand operand, Instruction instruction |
operand = node.asOperand() and
instruction = operand.getUse()
|
result = instruction.getResultId() + "." + operand.getDumpId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
result = "var(" + node.asVariable().getQualifiedName() + ")" and
order1 = 1000000 and
order2 = 0
}
private import PrintIRUtilities

/**
* Gets the local dataflow from other nodes in the same function to this node.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Print the dataflow local store steps in IR dumps.
*/

private import cpp
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
// that the cached IR gets the same checksum here as it does in queries that use
// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import PrintIRUtilities

/**
* Property provider for local IR dataflow store steps.
*/
class LocalFlowPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instruction, string key) {
exists(DataFlow::Node objectNode, Content content |
key = "content[" + content.toString() + "]" and
instruction = objectNode.asInstruction() and
result =
strictconcat(string element, DataFlow::Node fieldNode |
storeStep(fieldNode, content, objectNode) and
element = nodeId(fieldNode, _, _)
|
element, ", "
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Shared utilities used when printing dataflow annotations in IR dumps.
*/

private import cpp
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
// that the cached IR gets the same checksum here as it does in queries that use
// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow

/**
* Gets a short ID for an IR dataflow node.
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
* instruction and a dot (e.g. `m128.left`).
* - For `Variable`s, this is the qualified name of the variable.
*/
string nodeId(DataFlow::Node node, int order1, int order2) {
exists(Instruction instruction | instruction = node.asInstruction() |
result = instruction.getResultId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
exists(Operand operand, Instruction instruction |
operand = node.asOperand() and
instruction = operand.getUse()
|
result = instruction.getResultId() + "." + operand.getDumpId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
result = "var(" + node.asVariable().getQualifiedName() + ")" and
order1 = 1000000 and
order2 = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Predicates to compute the modeled side effects of calls during IR construction.
*
* These are used in `TranslatedElement.qll` to generate the `TTranslatedSideEffect` instances, and
* also in `TranslatedCall.qll` to inject the actual side effect instructions.
*/

private import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.models.interfaces.SideEffect

/**
* Holds if the specified call has a side effect that does not come from a `SideEffectFunction`
* model.
*/
private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buffer, boolean isWrite) {
not call.getTarget() instanceof SideEffectFunction and
(
exists(MemberFunction mfunc |
// A non-static member function, including a constructor or destructor, may write to `*this`,
// and may also read from `*this` if it is not a constructor.
i = -1 and
mfunc = call.getTarget() and
not mfunc.isStatic() and
buffer = false and
(
isWrite = false and not mfunc instanceof Constructor
or
isWrite = true and not mfunc instanceof ConstMemberFunction
)
)
or
exists(Expr expr |
// A pointer-like argument is assumed to read from the pointed-to buffer, and may write to the
// buffer as well unless the pointer points to a `const` value.
i >= 0 and
buffer = true and
expr = call.getArgument(i).getFullyConverted() and
exists(Type t | t = expr.getUnspecifiedType() |
t instanceof ArrayType or
t instanceof PointerType or
t instanceof ReferenceType
) and
(
isWrite = true and
not call.getTarget().getParameter(i).getType().isDeeplyConstBelow()
or
isWrite = false
)
)
)
}

/**
* Returns a side effect opcode for parameter index `i` of the specified call.
*
* This predicate will return at most two results: one read side effect, and one write side effect.
*/
Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
exists(boolean buffer |
(
call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(i, buffer)
or
not call.getTarget() instanceof SideEffectFunction and
hasDefaultSideEffect(call, i, buffer, false)
) and
if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(i))
then (
buffer = true and
result instanceof Opcode::SizedBufferReadSideEffect
) else (
buffer = false and result instanceof Opcode::IndirectReadSideEffect
or
buffer = true and result instanceof Opcode::BufferReadSideEffect
)
)
or
exists(boolean buffer, boolean mustWrite |
(
call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(i, buffer, mustWrite)
or
not call.getTarget() instanceof SideEffectFunction and
hasDefaultSideEffect(call, i, buffer, true) and
mustWrite = false
) and
if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(i))
then (
buffer = true and
mustWrite = false and
result instanceof Opcode::SizedBufferMayWriteSideEffect
or
buffer = true and
mustWrite = true and
result instanceof Opcode::SizedBufferMustWriteSideEffect
) else (
buffer = false and
mustWrite = false and
result instanceof Opcode::IndirectMayWriteSideEffect
or
buffer = false and
mustWrite = true and
result instanceof Opcode::IndirectMustWriteSideEffect
or
buffer = true and mustWrite = false and result instanceof Opcode::BufferMayWriteSideEffect
or
buffer = true and mustWrite = true and result instanceof Opcode::BufferMustWriteSideEffect
)
)
}
Loading