mirror of
https://github.com/github/codeql.git
synced 2026-03-30 20:28:15 +02:00
Merge branch 'main' of https://github.com/github/codeql into oscarsj/merge-back-rc-3.21
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Tag extends @tag {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where
|
||||
in_trap_or_tag(e, trap)
|
||||
or
|
||||
exists(Tag tag |
|
||||
in_trap_or_tag(e, tag) and
|
||||
trap_uses_tag(trap, tag)
|
||||
)
|
||||
select e, trap
|
||||
2545
cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
Normal file
2545
cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
class SourceFile extends @source_file {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from SourceFile source_file, string name, Trap trap
|
||||
where
|
||||
source_file_uses_trap(source_file, trap) and
|
||||
source_file_name(source_file, name)
|
||||
select name, trap
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_file_uses_trap.ql
|
||||
source_file_name.rel: delete
|
||||
tag_name.rel: delete
|
||||
trap_uses_tag.rel: delete
|
||||
in_trap.rel: run in_trap.ql
|
||||
in_trap_or_tag.rel: delete
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
@@ -555,6 +555,7 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
|
||||
* Normalize the `n`'th parameter of `f` by replacing template names
|
||||
* with `func:N` (where `N` is the index of the template).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
|
||||
@@ -201,7 +201,7 @@ module SourceSinkInterpretationInput implements
|
||||
string toString() {
|
||||
result = this.asElement().toString()
|
||||
or
|
||||
result = this.asNode().toString()
|
||||
result = this.asNode().toStringImpl()
|
||||
or
|
||||
result = this.asCall().toString()
|
||||
}
|
||||
|
||||
1823
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
Normal file
1823
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
private import cpp as Cpp
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
@@ -16,28 +17,42 @@ private import semmle.code.cpp.dataflow.ExternalFlow as External
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
module Nodes0 {
|
||||
cached
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
|
||||
cached
|
||||
string toStringCached(Node n) {
|
||||
result = toExprString(n)
|
||||
or
|
||||
not exists(toExprString(n)) and
|
||||
result = n.toStringImpl()
|
||||
}
|
||||
|
||||
cached
|
||||
Location getLocationCached(Node n) { result = n.getLocationImpl() }
|
||||
|
||||
cached
|
||||
newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/**
|
||||
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
||||
* an additional forward or backwards branching factor that is not taken into account
|
||||
@@ -59,38 +74,174 @@ private module Cached {
|
||||
result = countNumberOfBranchesUsingParameter(switch, p)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
private import Nodes0
|
||||
cached
|
||||
newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A module for calculating the number of stars (i.e., `*`s) needed for various
|
||||
* dataflow node `toString` predicates.
|
||||
*/
|
||||
module NodeStars {
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
cached
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
cached
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
cached
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
cached
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d |
|
||||
d.impliesClearOf(c) and storeStepImpl(_, d, pun, true)
|
||||
|
|
||||
pun
|
||||
).getPreUpdateNode() and
|
||||
(
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import NodeStars
|
||||
import Cached
|
||||
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
|
||||
/**
|
||||
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
|
||||
@@ -828,85 +979,10 @@ private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
|
||||
result = getMinIndirectionsForType(def.getUnspecifiedType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
pragma[inline_late]
|
||||
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise. This has to do with whether a
|
||||
* store step can be used to clear a field (see `clearsContent`).
|
||||
*/
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperandRec(
|
||||
Operand operandFrom, Operand operandTo, int ind, boolean certain
|
||||
) {
|
||||
@@ -957,63 +1033,6 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
|
||||
.getPreUpdateNode() and
|
||||
(
|
||||
// The crement operations and pointer addition and subtraction self-assign. We do not
|
||||
// want to clear the contents if it is indirectly pointed at by any of these operations,
|
||||
// as part of the contents might still be accessible afterwards. If there is no such
|
||||
// indirection clearing the contents is safe.
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
@@ -1046,11 +1065,6 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A callable, which may be:
|
||||
* - a function (that may contain code)
|
||||
@@ -1134,15 +1148,6 @@ class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
|
||||
sc.asSummarizedCallable().hasManualModel()
|
||||
}
|
||||
@@ -1523,12 +1528,6 @@ private predicate fieldHasApproxName(Field f, string s) {
|
||||
|
||||
private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().charAt(0) }
|
||||
|
||||
cached
|
||||
private newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/** An approximated `Content`. */
|
||||
class ContentApprox extends TContentApprox {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -73,17 +73,9 @@ private module Cached {
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
@@ -112,10 +104,10 @@ private module Cached {
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
exists(StoreInstruction store |
|
||||
store = instr and
|
||||
IRConstruction::Raw::instructionProducesExprResult(store) and
|
||||
result = asDefinitionImpl0(store)
|
||||
)
|
||||
or
|
||||
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
|
||||
@@ -145,18 +137,9 @@ private module Cached {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,11 +149,7 @@ private module Cached {
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
IRConstruction::Raw::isConditionalExprTempStore(store)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import PrintIRUtilities
|
||||
|
||||
/** A property provider for local IR dataflow store steps. */
|
||||
|
||||
@@ -2,6 +2,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import SsaImpl as Ssa
|
||||
private import PrintIRUtilities
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
private Instruction getInstruction(Node n, string stars) {
|
||||
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
|
||||
|
||||
@@ -10,8 +10,9 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
import SsaImplCommon
|
||||
|
||||
private module SourceVariables {
|
||||
@@ -438,10 +439,7 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
|
||||
* initialize `v`.
|
||||
*/
|
||||
private Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
exists(TranslatedVariableInitialization init |
|
||||
init.getIRVariable() = v and
|
||||
result = init.getTargetAddress()
|
||||
)
|
||||
result = IRConstruction::Raw::getInitializationTargetAddress(v)
|
||||
}
|
||||
|
||||
/** An initial definition of an SSA variable address. */
|
||||
|
||||
@@ -4,47 +4,12 @@ import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
private import DataFlowPrivate
|
||||
private import TypeFlow
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognized as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of `this` in the member function `f`.
|
||||
* The result is a glvalue if `isGLValue` is true, and
|
||||
@@ -55,26 +20,6 @@ private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) {
|
||||
result.hasType(f.getTypeOfThis(), isGLValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the operand `operand`.
|
||||
* This is equivalent to the type of the operand's defining instruction.
|
||||
@@ -347,10 +292,6 @@ predicate isWrite(Node0Impl value, Operand address, boolean certain) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
|
||||
}
|
||||
|
||||
newtype TBaseSourceVariable =
|
||||
// Each IR variable gets its own source variable
|
||||
TBaseIRVariable(IRVariable var) or
|
||||
@@ -572,6 +513,69 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognized as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
cached
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
cached
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
}
|
||||
|
||||
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
|
||||
private predicate isConversion(Operand op) {
|
||||
exists(Instruction def, Operand use |
|
||||
|
||||
@@ -5,64 +5,81 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
private import SsaImpl as Ssa
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step. This relation is only used for local taint flow
|
||||
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
|
||||
* special cases that should only apply to local taint flow.
|
||||
*/
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// dataflow step
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// taint flow step
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// models-as-data summarized flow for local data flow (i.e. special case for flow
|
||||
// through calls to modeled functions, without relying on global dataflow to join
|
||||
// the dots).
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
|
||||
cached
|
||||
private module Cached {
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
* This predicate exists to collapse the `cached` predicates in this module with the
|
||||
* `cached` predicates in other C/C++ dataflow files, which is then collapsed
|
||||
* with the `cached` predicates in `DataFlowImplCommon.qll`.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step. This relation is only used for local taint flow
|
||||
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
|
||||
* special cases that should only apply to local taint flow.
|
||||
*/
|
||||
cached
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// dataflow step
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// taint flow step
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// models-as-data summarized flow for local data flow (i.e. special case for flow
|
||||
// through calls to modeled functions, without relying on global dataflow to join
|
||||
// the dots).
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
or
|
||||
// object->field conflation for content that is a `TaintInheritingContent`.
|
||||
exists(DataFlow::ContentSet f |
|
||||
readStep(nodeFrom, f, nodeTo) and
|
||||
f.getAReadContent() instanceof TaintInheritingContent
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
or
|
||||
// object->field conflation for content that is a `TaintInheritingContent`.
|
||||
exists(DataFlow::ContentSet f |
|
||||
readStep(nodeFrom, f, nodeTo) and
|
||||
f.getAReadContent() instanceof TaintInheritingContent
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
@@ -196,7 +213,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
|
||||
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
|
||||
// to that output, but the deref is not modeled in the IR for the caller.
|
||||
exists(
|
||||
CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func,
|
||||
CallInstruction call, SideEffectOperandNode indirectArgument, Function func,
|
||||
FunctionInput modelIn, FunctionOutput modelOut
|
||||
|
|
||||
indirectArgument = callInput(call, modelIn) and
|
||||
|
||||
@@ -15,6 +15,7 @@ private import TranslatedCall
|
||||
private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
private import TranslatedGlobalVar
|
||||
private import TranslatedInitialization
|
||||
|
||||
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||
instruction = TRawInstruction(result, _)
|
||||
@@ -194,6 +195,89 @@ module Raw {
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with the instruction `instr` that computes
|
||||
* the `Convert` instruction on the extent expression of an allocation.
|
||||
*/
|
||||
cached
|
||||
Expr getAllocationExtentConvertExpr(Instruction instr) {
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag()) and
|
||||
result = tas.getExtent().getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ParenthesisExpr` associated with a transparent conversion
|
||||
* instruction, if any.
|
||||
*/
|
||||
cached
|
||||
ParenthesisExpr getTransparentConversionParenthesisExpr(Instruction instr) {
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr() and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` belongs to a `TranslatedCoreExpr` that produces an
|
||||
* expression result. This indicates that the instruction represents a
|
||||
* definition whose result should be mapped back to the expression.
|
||||
*/
|
||||
cached
|
||||
predicate instructionProducesExprResult(Instruction instr) {
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with a `StoreInstruction` generated
|
||||
* by an `TranslatedAssignOperation`.
|
||||
*/
|
||||
cached
|
||||
Expr getAssignOperationStoreExpr(StoreInstruction store) {
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with a `StoreInstruction` generated
|
||||
* by an `TranslatedCrementOperation`.
|
||||
*/
|
||||
cached
|
||||
Expr getCrementOperationStoreExpr(StoreInstruction store) {
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `store` is a `StoreInstruction` that defines the temporary
|
||||
* `IRVariable` generated as part of the translation of a ternary expression.
|
||||
*/
|
||||
cached
|
||||
predicate isConditionalExprTempStore(StoreInstruction store) {
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the instruction that computes the address used to initialize `v`. */
|
||||
cached
|
||||
Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
exists(TranslatedVariableInitialization init |
|
||||
init.getIRVariable() = v and
|
||||
result = init.getTargetAddress()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
|
||||
|
||||
@@ -245,6 +245,25 @@ trap_filename(
|
||||
string filename: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Gives the tag name for `tag`.
|
||||
* For debugging only.
|
||||
*/
|
||||
tag_name(
|
||||
int tag: @tag,
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
@trap_or_tag = @tag | @trap;
|
||||
|
||||
/**
|
||||
* Gives the name for the source file.
|
||||
*/
|
||||
source_file_name(
|
||||
int sf: @source_file,
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* In `build-mode: none` overlay mode, indicates that `source_file`
|
||||
* (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
|
||||
@@ -252,16 +271,25 @@ trap_filename(
|
||||
* includes, or a template instantiation it transitively uses.
|
||||
*/
|
||||
source_file_uses_trap(
|
||||
string source_file: string ref,
|
||||
int source_file: @source_file ref,
|
||||
int trap_file: @trap ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if there is a definition of `element` in TRAP file `trap_file`.
|
||||
* In `build-mode: none` overlay mode, indicates that the TRAP file
|
||||
* `trap_file` uses tag `tag`.
|
||||
*/
|
||||
in_trap(
|
||||
trap_uses_tag(
|
||||
int trap_file: @trap ref,
|
||||
int tag: @tag ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if there is a definition of `element` in TRAP file or tag `t`.
|
||||
*/
|
||||
in_trap_or_tag(
|
||||
int element: @element ref,
|
||||
int trap_file: @trap ref
|
||||
int t: @trap_or_tag ref
|
||||
);
|
||||
|
||||
pch_uses(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where in_trap(e, trap)
|
||||
select e, trap
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
newtype TSourceFile = MkSourceFile(string name) { source_file_uses_trap(name, _) }
|
||||
|
||||
module FreshSourceFile = QlBuiltins::NewEntity<TSourceFile>;
|
||||
|
||||
class SourceFile extends FreshSourceFile::EntityId {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
query predicate mk_source_file_name(SourceFile source_file, string name) {
|
||||
source_file = FreshSourceFile::map(MkSourceFile(name))
|
||||
}
|
||||
|
||||
query predicate mk_source_file_uses_trap(SourceFile source_file, Trap trap) {
|
||||
exists(string name |
|
||||
source_file_uses_trap(name, trap) and
|
||||
mk_source_file_name(source_file, name)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_files.ql mk_source_file_uses_trap
|
||||
source_file_name.rel: run source_files.ql mk_source_file_name
|
||||
in_trap.rel: delete
|
||||
in_trap_or_tag.rel: run in_trap_or_tag.ql
|
||||
@@ -15,6 +15,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
/** Gets a loop that contains `e`. */
|
||||
Loop getAnEnclosingLoopOfExpr(Expr e) { result = getAnEnclosingLoopOfStmt(e.getEnclosingStmt()) }
|
||||
@@ -45,9 +46,9 @@ private Expr getExpr(DataFlow::Node node) {
|
||||
or
|
||||
result = node.asOperand().getUse().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
|
||||
result = node.(RawIndirectInstruction).getInstruction().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
|
||||
result = node.(RawIndirectOperand).getOperand().getUse().getAst()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +209,7 @@ class LoopWithAlloca extends Stmt {
|
||||
this.conditionRequiresInequality(va, _, _) and
|
||||
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
|
||||
// Phi nodes will be preceded by nodes that represent actual definitions
|
||||
not result instanceof DataFlow::SsaSynthNode and
|
||||
not result instanceof SsaSynthNode and
|
||||
// A source is outside the loop if it's not inside the loop
|
||||
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as DataFlowNodes
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import semmle.code.cpp.dataflow.new.TaintTracking as Tt
|
||||
@@ -403,7 +404,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||
}
|
||||
|
||||
predicate apiSource(DataFlow::Node source) {
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1)
|
||||
or
|
||||
source instanceof DataFlow::ParameterNode
|
||||
}
|
||||
@@ -416,7 +417,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
|
||||
)
|
||||
or
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1) and
|
||||
result = qualifierString()
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
{
|
||||
C *c = new C();
|
||||
B *b = B::make(c);
|
||||
sink(b->c); // $ast,ir
|
||||
sink(b->c); // $ ast,ir
|
||||
}
|
||||
|
||||
void f2()
|
||||
|
||||
@@ -26,9 +26,9 @@ public:
|
||||
|
||||
void func()
|
||||
{
|
||||
sink(s1); // $ast,ir
|
||||
sink(s1); // $ ast,ir
|
||||
sink(s2); // $ MISSING: ast,ir
|
||||
sink(s3); // $ast,ir
|
||||
sink(s3); // $ ast,ir
|
||||
sink(s4); // $ MISSING: ast,ir
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
};
|
||||
|
||||
static void sinkWrap(Box2* b2) {
|
||||
sink(b2->getBox1()->getElem()); // $ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
|
||||
sink(b2->getBox1()->getElem()); // $ ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
|
||||
}
|
||||
|
||||
Box2* boxfield;
|
||||
|
||||
@@ -48,25 +48,25 @@ struct S {
|
||||
void test_setDirectly() {
|
||||
S s;
|
||||
s.setDirectly(user_input());
|
||||
sink(s.getDirectly()); // $ast ir
|
||||
sink(s.getDirectly()); // $ ast ir
|
||||
}
|
||||
|
||||
void test_setIndirectly() {
|
||||
S s;
|
||||
s.setIndirectly(user_input());
|
||||
sink(s.getIndirectly()); // $ast ir
|
||||
sink(s.getIndirectly()); // $ ast ir
|
||||
}
|
||||
|
||||
void test_setThroughNonMember() {
|
||||
S s;
|
||||
s.setThroughNonMember(user_input());
|
||||
sink(s.getThroughNonMember()); // $ast ir
|
||||
sink(s.getThroughNonMember()); // $ ast ir
|
||||
}
|
||||
|
||||
void test_nonMemberSetA() {
|
||||
S s;
|
||||
nonMemberSetA(&s, user_input());
|
||||
sink(nonMemberGetA(&s)); // $ast,ir
|
||||
sink(nonMemberGetA(&s)); // $ ast,ir
|
||||
}
|
||||
|
||||
////////////////////
|
||||
@@ -112,7 +112,7 @@ void test_outer_with_ptr(Outer *pouter) {
|
||||
sink(outer.a); // $ ast,ir
|
||||
|
||||
sink(pouter->inner_nested.a); // $ ast,ir
|
||||
sink(pouter->inner_ptr->a); // $ast,ir
|
||||
sink(pouter->inner_ptr->a); // $ ast,ir
|
||||
sink(pouter->a); // $ ast,ir
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ void single_field_test()
|
||||
A a;
|
||||
a.i = user_input();
|
||||
A a2 = a;
|
||||
sink(a2.i); //$ ast,ir
|
||||
sink(a2.i); // $ ast,ir
|
||||
}
|
||||
|
||||
struct C {
|
||||
@@ -81,7 +81,7 @@ struct C2
|
||||
|
||||
void m() {
|
||||
f2.f1 = user_input();
|
||||
sink(getf2f1()); //$ ast,ir
|
||||
sink(getf2f1()); // $ ast,ir
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ void single_field_test_typedef(A_typedef a)
|
||||
{
|
||||
a.i = user_input();
|
||||
A_typedef a2 = a;
|
||||
sink(a2.i); //$ ast,ir
|
||||
sink(a2.i); // $ ast,ir
|
||||
}
|
||||
|
||||
namespace TestAdditionalCallTargets {
|
||||
@@ -168,4 +168,4 @@ void test_union_with_two_instantiations_of_different_sizes() {
|
||||
sink(u_int.y); // $ MISSING: ir
|
||||
}
|
||||
|
||||
} // namespace Simple
|
||||
} // namespace Simple
|
||||
|
||||
@@ -12,14 +12,14 @@ struct Outer {
|
||||
};
|
||||
|
||||
void absink(struct AB *ab) {
|
||||
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
|
||||
sink(ab->a); // $ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
|
||||
sink(ab->b); // no flow
|
||||
}
|
||||
|
||||
int struct_init(void) {
|
||||
struct AB ab = { user_input(), 0 };
|
||||
|
||||
sink(ab.a); //$ ast,ir
|
||||
sink(ab.a); // $ ast,ir
|
||||
sink(ab.b); // no flow
|
||||
absink(&ab);
|
||||
|
||||
@@ -28,9 +28,9 @@ int struct_init(void) {
|
||||
&ab,
|
||||
};
|
||||
|
||||
sink(outer.nestedAB.a); //$ ast,ir
|
||||
sink(outer.nestedAB.a); // $ ast,ir
|
||||
sink(outer.nestedAB.b); // no flow
|
||||
sink(outer.pointerAB->a); //$ ast,ir
|
||||
sink(outer.pointerAB->a); // $ ast,ir
|
||||
sink(outer.pointerAB->b); // no flow
|
||||
|
||||
absink(&outer.nestedAB);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import testModels
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
string describe(DataFlow::Node n) {
|
||||
n instanceof ParameterNode and result = "ParameterNode"
|
||||
|
||||
@@ -75,7 +75,7 @@ void test_sources() {
|
||||
int e = localMadSource();
|
||||
sink(e); // $ ir
|
||||
|
||||
sink(MyNamespace::namespaceLocalMadSource()); // $: ir
|
||||
sink(MyNamespace::namespaceLocalMadSource()); // $ ir
|
||||
sink(MyNamespace::namespaceLocalMadSourceVar); // $ ir
|
||||
sink(MyNamespace::MyNamespace2::namespace2LocalMadSource()); // $ ir
|
||||
sink(MyNamespace::localMadSource()); // $ (the MyNamespace version of this function is not a source)
|
||||
@@ -475,4 +475,4 @@ void test_receive_array() {
|
||||
int array[10] = {x};
|
||||
int y = receive_array(array);
|
||||
sink(y); // $ ir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ void test_qualifiers()
|
||||
b.member = source();
|
||||
sink(b); // $ ir MISSING: ast
|
||||
sink(b.member); // $ ast,ir
|
||||
sink(b.getMember()); // $ MISSING: ir ast
|
||||
sink(b.getMember()); // $ MISSING: ir ast
|
||||
|
||||
c = new MyClass2(0);
|
||||
|
||||
@@ -865,4 +865,4 @@ void test_iconv(size_t size) {
|
||||
size_t size_out;
|
||||
iconv(0, &s, &size, &p, &size_out);
|
||||
sink(*p); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,64 +24,64 @@ struct DerivedVI : virtual Base1 {
|
||||
};
|
||||
|
||||
void Locals() {
|
||||
Point pt = { //$ussa=pt
|
||||
1, //$ussa=pt[0..4)<int>
|
||||
2 //$ussa=pt[4..8)<int>
|
||||
Point pt = { // $ ussa=pt
|
||||
1, // $ ussa=pt[0..4)<int>
|
||||
2 // $ ussa=pt[4..8)<int>
|
||||
};
|
||||
int i = pt.x; //$ussa=pt[0..4)<int>
|
||||
i = pt.y; //$ussa=pt[4..8)<int>
|
||||
int i = pt.x; // $ ussa=pt[0..4)<int>
|
||||
i = pt.y; // $ ussa=pt[4..8)<int>
|
||||
int* p = &pt.x;
|
||||
i = *p; //$ussa=pt[0..4)<int>
|
||||
i = *p; // $ ussa=pt[0..4)<int>
|
||||
p = &pt.y;
|
||||
i = *p; //$ussa=pt[4..8)<int>
|
||||
i = *p; // $ ussa=pt[4..8)<int>
|
||||
}
|
||||
|
||||
void PointsTo(
|
||||
int a, //$raw=a
|
||||
Point& b, //$raw=b ussa=*b
|
||||
Point* c, //$raw=c ussa=*c
|
||||
int* d, //$raw=d ussa=*d
|
||||
DerivedSI* e, //$raw=e ussa=*e
|
||||
DerivedMI* f, //$raw=f ussa=*f
|
||||
DerivedVI* g //$raw=g ussa=*g
|
||||
int a, // $ raw=a
|
||||
Point& b, // $ raw=b ussa=*b
|
||||
Point* c, // $ raw=c ussa=*c
|
||||
int* d, // $ raw=d ussa=*d
|
||||
DerivedSI* e, // $ raw=e ussa=*e
|
||||
DerivedMI* f, // $ raw=f ussa=*f
|
||||
DerivedVI* g // $ raw=g ussa=*g
|
||||
) {
|
||||
|
||||
int i = a; //$raw=a
|
||||
i = *&a; //$raw=a
|
||||
i = *(&a + 0); //$raw=a
|
||||
i = b.x; //$raw=b ussa=*b[0..4)<int>
|
||||
i = b.y; //$raw=b ussa=*b[4..8)<int>
|
||||
i = c->x; //$raw=c ussa=*c[0..4)<int>
|
||||
i = c->y; //$raw=c ussa=*c[4..8)<int>
|
||||
i = *d; //$raw=d ussa=*d[0..4)<int>
|
||||
i = *(d + 0); //$raw=d ussa=*d[0..4)<int>
|
||||
i = d[5]; //$raw=d ussa=*d[20..24)<int>
|
||||
i = 5[d]; //$raw=d ussa=*d[20..24)<int>
|
||||
i = d[a]; //$raw=d raw=a ussa=*d[?..?)<int>
|
||||
i = a[d]; //$raw=d raw=a ussa=*d[?..?)<int>
|
||||
int i = a; // $ raw=a
|
||||
i = *&a; // $ raw=a
|
||||
i = *(&a + 0); // $ raw=a
|
||||
i = b.x; // $ raw=b ussa=*b[0..4)<int>
|
||||
i = b.y; // $ raw=b ussa=*b[4..8)<int>
|
||||
i = c->x; // $ raw=c ussa=*c[0..4)<int>
|
||||
i = c->y; // $ raw=c ussa=*c[4..8)<int>
|
||||
i = *d; // $ raw=d ussa=*d[0..4)<int>
|
||||
i = *(d + 0); // $ raw=d ussa=*d[0..4)<int>
|
||||
i = d[5]; // $ raw=d ussa=*d[20..24)<int>
|
||||
i = 5[d]; // $ raw=d ussa=*d[20..24)<int>
|
||||
i = d[a]; // $ raw=d raw=a ussa=*d[?..?)<int>
|
||||
i = a[d]; // $ raw=d raw=a ussa=*d[?..?)<int>
|
||||
|
||||
int* p = &b.x; //$raw=b
|
||||
i = *p; //$ussa=*b[0..4)<int>
|
||||
p = &b.y; //$raw=b
|
||||
i = *p; //$ussa=*b[4..8)<int>
|
||||
p = &c->x; //$raw=c
|
||||
i = *p; //$ussa=*c[0..4)<int>
|
||||
p = &c->y; //$raw=c
|
||||
i = *p; //$ussa=*c[4..8)<int>
|
||||
p = &d[5]; //$raw=d
|
||||
i = *p; //$ussa=*d[20..24)<int>
|
||||
p = &d[a]; //$raw=d raw=a
|
||||
i = *p; //$ussa=*d[?..?)<int>
|
||||
int* p = &b.x; // $ raw=b
|
||||
i = *p; // $ ussa=*b[0..4)<int>
|
||||
p = &b.y; // $ raw=b
|
||||
i = *p; // $ ussa=*b[4..8)<int>
|
||||
p = &c->x; // $ raw=c
|
||||
i = *p; // $ ussa=*c[0..4)<int>
|
||||
p = &c->y; // $ raw=c
|
||||
i = *p; // $ ussa=*c[4..8)<int>
|
||||
p = &d[5]; // $ raw=d
|
||||
i = *p; // $ ussa=*d[20..24)<int>
|
||||
p = &d[a]; // $ raw=d raw=a
|
||||
i = *p; // $ ussa=*d[?..?)<int>
|
||||
|
||||
Point* q = &c[a]; //$raw=c raw=a
|
||||
i = q->x; //$ussa=*c[?..?)<int>
|
||||
i = q->y; //$ussa=*c[?..?)<int>
|
||||
Point* q = &c[a]; // $ raw=c raw=a
|
||||
i = q->x; // $ ussa=*c[?..?)<int>
|
||||
i = q->y; // $ ussa=*c[?..?)<int>
|
||||
|
||||
i = e->b1; //$raw=e ussa=*e[0..4)<int>
|
||||
i = e->dsi; //$raw=e ussa=*e[4..8)<int>
|
||||
i = f->b1; //$raw=f ussa=*f[0..4)<int>
|
||||
i = f->b2; //$raw=f ussa=*f[4..8)<int>
|
||||
i = f->dmi; //$raw=f ussa=*f[8..12)<int>
|
||||
i = g->b1; //$raw=g ussa=*g[?..?)<int>
|
||||
i = g->dvi; //$raw=g ussa=*g[8..12)<int>
|
||||
}
|
||||
i = e->b1; // $ raw=e ussa=*e[0..4)<int>
|
||||
i = e->dsi; // $ raw=e ussa=*e[4..8)<int>
|
||||
i = f->b1; // $ raw=f ussa=*f[0..4)<int>
|
||||
i = f->b2; // $ raw=f ussa=*f[4..8)<int>
|
||||
i = f->dmi; // $ raw=f ussa=*f[8..12)<int>
|
||||
i = g->b1; // $ raw=g ussa=*g[?..?)<int>
|
||||
i = g->dvi; // $ raw=g ussa=*g[8..12)<int>
|
||||
}
|
||||
|
||||
@@ -10,24 +10,24 @@ struct S {
|
||||
|
||||
void unique_ptr_init(S s) {
|
||||
unique_ptr<S> p(new S); // MISSING: $ussa=dynamic{1}
|
||||
int i = (*p).x; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
int i = (*p).x; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
unique_ptr<S> q = std::move(p);
|
||||
*(q.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(q.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> t(std::move(q));
|
||||
t->x = 5; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
t->x = 5; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
}
|
||||
|
||||
void shared_ptr_init(S s) {
|
||||
shared_ptr<S> p(new S); //$ MISSING: ussa=dynamic{1}
|
||||
int i = (*p).x; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> p(new S); // $ MISSING: ussa=dynamic{1}
|
||||
int i = (*p).x; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> q = std::move(p);
|
||||
*(q.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(q.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> t(q);
|
||||
t->x = 5; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
t->x = 5; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ int test4() {
|
||||
}
|
||||
range(total); // $ MISSING: range=>=0
|
||||
range(i); // $ range===2
|
||||
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
return total + i;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ int test14(int x) {
|
||||
int x3 = (int)(unsigned int)x;
|
||||
range(x3);
|
||||
char c0 = x;
|
||||
range(c0);
|
||||
range(c0);
|
||||
unsigned short s0 = x;
|
||||
range(s0);
|
||||
range(x0 + x1 + x2 + x3 + c0 + s0); // $ overflow=+ overflow=+-
|
||||
@@ -218,7 +218,7 @@ int test14(int x) {
|
||||
}
|
||||
|
||||
long long test15(long long x) {
|
||||
return (x > 0 && (range(x), x == (int)x)) ? // $ range=>=1
|
||||
return (x > 0 && (range(x), x == (int)x)) ? // $ range=>=1
|
||||
(range(x), x) : // $ range=>=1
|
||||
(range(x), -1);
|
||||
}
|
||||
@@ -228,7 +228,7 @@ int test_unary(int a) {
|
||||
int total = 0;
|
||||
|
||||
if (3 <= a && a <= 11) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
int b = +a;
|
||||
range(b); // $ range=<=11 range=>=3
|
||||
int c = -a;
|
||||
@@ -384,7 +384,7 @@ int test_mult02(int a, int b) {
|
||||
total += r;
|
||||
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
}
|
||||
range(total); // $range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -467,7 +467,7 @@ int test_mult04(int a, int b) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
range(b); // $ range=<=0 range=>=-13
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=Phi: - ...+221"
|
||||
}
|
||||
@@ -1030,7 +1030,7 @@ void test_negate_signed(int s) {
|
||||
}
|
||||
}
|
||||
|
||||
// By setting the guard after the use in another guard we
|
||||
// By setting the guard after the use in another guard we
|
||||
// don't get the useful information
|
||||
void test_guard_after_use(int pos, int size, int offset) {
|
||||
if (pos + offset >= size) { // $ overflow=+-
|
||||
@@ -1040,12 +1040,12 @@ void test_guard_after_use(int pos, int size, int offset) {
|
||||
return;
|
||||
}
|
||||
range(pos + 1); // $ overflow=+ range="==InitializeParameter: pos+1" MISSING: range="<=InitializeParameter: size-1"
|
||||
}
|
||||
}
|
||||
|
||||
int cond();
|
||||
|
||||
|
||||
// This is basically what we get when we have a loop that calls
|
||||
// This is basically what we get when we have a loop that calls
|
||||
// realloc in some iterations
|
||||
void alloc_in_loop(int origLen) {
|
||||
if (origLen <= 10) {
|
||||
@@ -1066,12 +1066,12 @@ void alloc_in_loop(int origLen) {
|
||||
}
|
||||
}
|
||||
|
||||
// This came from a case where it handled the leftovers before an unrolled loop
|
||||
// This came from a case where it handled the leftovers before an unrolled loop
|
||||
void mask_at_start(int len) {
|
||||
if (len < 0) {
|
||||
return;
|
||||
}
|
||||
int leftOver = len & 63;
|
||||
int leftOver = len & 63;
|
||||
for (int i = 0; i < leftOver; i++) {
|
||||
range(i); // $ range=<=62 range=>=0 range="<=Store: ... & ... | Store: leftOver-1" range="<=InitializeParameter: len-1"
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
void Complex(void) {
|
||||
_Complex float cf; //$irtype=cfloat8
|
||||
_Complex double cd; //$irtype=cfloat16
|
||||
_Complex long double cld; //$irtype=cfloat32
|
||||
_Complex float cf; // $ irtype=cfloat8
|
||||
_Complex double cd; // $ irtype=cfloat16
|
||||
_Complex long double cld; // $ irtype=cfloat32
|
||||
// _Complex __float128 cf128;
|
||||
}
|
||||
|
||||
void Imaginary(void) {
|
||||
_Imaginary float jf; //$irtype=ifloat4
|
||||
_Imaginary double jd; //$irtype=ifloat8
|
||||
_Imaginary long double jld; //$irtype=ifloat16
|
||||
_Imaginary float jf; // $ irtype=ifloat4
|
||||
_Imaginary double jd; // $ irtype=ifloat8
|
||||
_Imaginary long double jld; // $ irtype=ifloat16
|
||||
// _Imaginary __float128 jf128;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,44 +22,44 @@ enum class ScopedE {
|
||||
};
|
||||
|
||||
void IRTypes() {
|
||||
char c; //$irtype=int1
|
||||
signed char sc; //$irtype=int1
|
||||
unsigned char uc; //$irtype=uint1
|
||||
short s; //$irtype=int2
|
||||
signed short ss; //$irtype=int2
|
||||
unsigned short us; //$irtype=uint2
|
||||
int i; //$irtype=int4
|
||||
signed int si; //$irtype=int4
|
||||
unsigned int ui; //$irtype=uint4
|
||||
long l; //$irtype=int8
|
||||
signed long sl; //$irtype=int8
|
||||
unsigned long ul; //$irtype=uint8
|
||||
long long ll; //$irtype=int8
|
||||
signed long long sll; //$irtype=int8
|
||||
unsigned long long ull; //$irtype=uint8
|
||||
bool b; //$irtype=bool1
|
||||
float f; //$irtype=float4
|
||||
double d; //$irtype=float8
|
||||
long double ld; //$irtype=float16
|
||||
__float128 f128; //$irtype=float16
|
||||
char c; // $ irtype=int1
|
||||
signed char sc; // $ irtype=int1
|
||||
unsigned char uc; // $ irtype=uint1
|
||||
short s; // $ irtype=int2
|
||||
signed short ss; // $ irtype=int2
|
||||
unsigned short us; // $ irtype=uint2
|
||||
int i; // $ irtype=int4
|
||||
signed int si; // $ irtype=int4
|
||||
unsigned int ui; // $ irtype=uint4
|
||||
long l; // $ irtype=int8
|
||||
signed long sl; // $ irtype=int8
|
||||
unsigned long ul; // $ irtype=uint8
|
||||
long long ll; // $ irtype=int8
|
||||
signed long long sll; // $ irtype=int8
|
||||
unsigned long long ull; // $ irtype=uint8
|
||||
bool b; // $ irtype=bool1
|
||||
float f; // $ irtype=float4
|
||||
double d; // $ irtype=float8
|
||||
long double ld; // $ irtype=float16
|
||||
__float128 f128; // $ irtype=float16
|
||||
|
||||
wchar_t wc; //$irtype=uint4
|
||||
// char8_t c8; //$irtype=uint1
|
||||
char16_t c16; //$irtype=uint2
|
||||
char32_t c32; //$irtype=uint4
|
||||
wchar_t wc; // $ irtype=uint4
|
||||
// char8_t c8; // $ irtype=uint1
|
||||
char16_t c16; // $ irtype=uint2
|
||||
char32_t c32; // $ irtype=uint4
|
||||
|
||||
int* pi; //$irtype=addr8
|
||||
int& ri = i; //$irtype=addr8
|
||||
void (*pfn)() = nullptr; //$irtype=func8
|
||||
void (&rfn)() = IRTypes; //$irtype=func8
|
||||
int* pi; // $ irtype=addr8
|
||||
int& ri = i; // $ irtype=addr8
|
||||
void (*pfn)() = nullptr; // $ irtype=func8
|
||||
void (&rfn)() = IRTypes; // $ irtype=func8
|
||||
|
||||
A s_a; //$irtype=opaque4{A}
|
||||
B s_b; //$irtype=opaque16{B}
|
||||
A s_a; // $ irtype=opaque4{A}
|
||||
B s_b; // $ irtype=opaque16{B}
|
||||
|
||||
E e; //$irtype=uint4
|
||||
ScopedE se; //$irtype=uint4
|
||||
E e; // $ irtype=uint4
|
||||
ScopedE se; // $ irtype=uint4
|
||||
|
||||
B a_b[10]; //$irtype=opaque160{B[10]}
|
||||
B a_b[10]; // $ irtype=opaque160{B[10]}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -1338,7 +1338,7 @@ void indirect_time_conversion_check(WORD year, WORD offset){
|
||||
void set_time(WORD year, WORD month, WORD day){
|
||||
SYSTEMTIME tmp;
|
||||
|
||||
tmp.wYear = year; //$ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
|
||||
tmp.wYear = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
|
||||
tmp.wMonth = month;
|
||||
tmp.wDay = day;
|
||||
}
|
||||
|
||||
@@ -44,5 +44,5 @@ NHibernate,3,,,,,,,,,,,,3,,,,,,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,,7,
|
||||
SourceGenerators,,,5,,,,,,,,,,,,,,,,,,,,5
|
||||
System,59,47,12495,,6,5,12,,,4,1,,31,2,,6,15,17,4,3,,6382,6113
|
||||
System,59,48,12495,,6,5,12,,,4,1,,31,2,,6,15,17,5,3,,6382,6113
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,,
|
||||
|
||||
|
@@ -8,7 +8,7 @@ C# framework & library support
|
||||
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",47,12495,59,5
|
||||
System,"``System.*``, ``System``",48,12495,59,5
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Http``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Data.SqlClient``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``NHibernate``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",60,2406,162,4
|
||||
Totals,,107,14908,415,9
|
||||
Totals,,108,14908,415,9
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Remove inclusion of @assign_expr in @bin_op
|
||||
compatibility: full
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
@@ -12,7 +13,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
internal class Constructor : Method
|
||||
{
|
||||
private readonly List<SyntaxNode> declaringReferenceSyntax;
|
||||
|
||||
private readonly Lazy<ConstructorDeclarationSyntax?> ordinaryConstructorSyntaxLazy;
|
||||
private readonly Lazy<TypeDeclarationSyntax?> primaryConstructorSyntaxLazy;
|
||||
private readonly Lazy<PrimaryConstructorBaseTypeSyntax?> primaryBaseLazy;
|
||||
private Constructor(Context cx, IMethodSymbol init)
|
||||
: base(cx, init)
|
||||
{
|
||||
@@ -20,8 +23,28 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Symbol.DeclaringSyntaxReferences
|
||||
.Select(r => r.GetSyntax())
|
||||
.ToList();
|
||||
ordinaryConstructorSyntaxLazy = new Lazy<ConstructorDeclarationSyntax?>(() =>
|
||||
declaringReferenceSyntax
|
||||
.OfType<ConstructorDeclarationSyntax>()
|
||||
.FirstOrDefault());
|
||||
primaryConstructorSyntaxLazy = new Lazy<TypeDeclarationSyntax?>(() =>
|
||||
declaringReferenceSyntax
|
||||
.OfType<TypeDeclarationSyntax>()
|
||||
.FirstOrDefault(t => t is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax));
|
||||
primaryBaseLazy = new Lazy<PrimaryConstructorBaseTypeSyntax?>(() =>
|
||||
PrimaryConstructorSyntax?
|
||||
.BaseList?
|
||||
.Types
|
||||
.OfType<PrimaryConstructorBaseTypeSyntax>()
|
||||
.FirstOrDefault());
|
||||
}
|
||||
|
||||
private ConstructorDeclarationSyntax? OrdinaryConstructorSyntax => ordinaryConstructorSyntaxLazy.Value;
|
||||
|
||||
private TypeDeclarationSyntax? PrimaryConstructorSyntax => primaryConstructorSyntaxLazy.Value;
|
||||
|
||||
private PrimaryConstructorBaseTypeSyntax? PrimaryBase => primaryBaseLazy.Value;
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMethod(trapFile);
|
||||
@@ -176,23 +199,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
init.PopulateArguments(trapFile, arguments, 0);
|
||||
}
|
||||
|
||||
private ConstructorDeclarationSyntax? OrdinaryConstructorSyntax =>
|
||||
declaringReferenceSyntax
|
||||
.OfType<ConstructorDeclarationSyntax>()
|
||||
.FirstOrDefault();
|
||||
|
||||
private TypeDeclarationSyntax? PrimaryConstructorSyntax =>
|
||||
declaringReferenceSyntax
|
||||
.OfType<TypeDeclarationSyntax>()
|
||||
.FirstOrDefault(t => t is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax);
|
||||
|
||||
private PrimaryConstructorBaseTypeSyntax? PrimaryBase =>
|
||||
PrimaryConstructorSyntax?
|
||||
.BaseList?
|
||||
.Types
|
||||
.OfType<PrimaryConstructorBaseTypeSyntax>()
|
||||
.FirstOrDefault();
|
||||
|
||||
private bool IsPrimary => PrimaryConstructorSyntax is not null;
|
||||
|
||||
// This is a default constructor in a class or struct declared in source.
|
||||
@@ -223,7 +229,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
case MethodKind.StaticConstructor:
|
||||
case MethodKind.Constructor:
|
||||
return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor);
|
||||
return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor.GetBodyDeclaringSymbol());
|
||||
default:
|
||||
throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 14: Added support for partial constructors.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added reverse taint flow from implicit conversion operator calls to their arguments.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `System.Net.WebSockets::ReceiveAsync` as a remote flow source.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
6
csharp/ql/lib/ext/System.Net.WebSockets.model.yml
Normal file
6
csharp/ql/lib/ext/System.Net.WebSockets.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["System.Net.WebSockets", "WebSocket", True, "ReceiveAsync", "", "", "Argument[0]", "remote", "manual"]
|
||||
@@ -142,6 +142,7 @@ private module GuardsInput implements
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate equalityTest(Expr eqtest, Expr left, Expr right, boolean polarity) {
|
||||
exists(ComparisonTest ct |
|
||||
ct.getExpr() = eqtest and
|
||||
@@ -410,6 +411,22 @@ private predicate typePattern(PatternMatch pm, TypePatternExpr tpe, Type t) {
|
||||
t = pm.getExpr().getType()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate dereferenceableExpr(Expr e, boolean isNullableType) {
|
||||
exists(Type t | t = e.getType() |
|
||||
t instanceof NullableType and
|
||||
isNullableType = true
|
||||
or
|
||||
t instanceof RefType and
|
||||
isNullableType = false
|
||||
)
|
||||
or
|
||||
exists(Expr parent |
|
||||
dereferenceableExpr(parent, isNullableType) and
|
||||
e = getNullEquivParent(parent)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that evaluates to a value that can be dereferenced. That is,
|
||||
* an expression that may evaluate to `null`.
|
||||
@@ -418,21 +435,12 @@ class DereferenceableExpr extends Expr {
|
||||
private boolean isNullableType;
|
||||
|
||||
DereferenceableExpr() {
|
||||
exists(Expr e, Type t |
|
||||
// There is currently a bug in the extractor: the type of `x?.Length` is
|
||||
// incorrectly `int`, while it should have been `int?`. We apply
|
||||
// `getNullEquivParent()` as a workaround
|
||||
this = getNullEquivParent*(e) and
|
||||
t = e.getType() and
|
||||
not this instanceof SwitchCaseExpr and
|
||||
not this instanceof PatternExpr
|
||||
|
|
||||
t instanceof NullableType and
|
||||
isNullableType = true
|
||||
or
|
||||
t instanceof RefType and
|
||||
isNullableType = false
|
||||
)
|
||||
// There is currently a bug in the extractor: the type of `x?.Length` is
|
||||
// incorrectly `int`, while it should have been `int?`. We apply
|
||||
// `getNullEquivParent()` as a workaround
|
||||
dereferenceableExpr(this, isNullableType) and
|
||||
not this instanceof SwitchCaseExpr and
|
||||
not this instanceof PatternExpr
|
||||
}
|
||||
|
||||
/** Holds if this expression has a nullable type `T?`. */
|
||||
|
||||
@@ -94,9 +94,19 @@ private Element getAChild(Element p) {
|
||||
result = p.(AssignOperation).getExpandedAssignment()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate astNode(Element e) {
|
||||
e = any(@top_level_exprorstmt_parent p | not p instanceof Attribute)
|
||||
or
|
||||
exists(Element parent |
|
||||
astNode(parent) and
|
||||
e = getAChild(parent)
|
||||
)
|
||||
}
|
||||
|
||||
/** An AST node. */
|
||||
class AstNode extends Element, TAstNode {
|
||||
AstNode() { this = getAChild*(any(@top_level_exprorstmt_parent p | not p instanceof Attribute)) }
|
||||
AstNode() { astNode(this) }
|
||||
|
||||
int getId() { idOf(this, result) }
|
||||
}
|
||||
|
||||
@@ -15,16 +15,47 @@ private class ControlFlowScope extends ControlFlowElement {
|
||||
predicate isNonExact() { exactScope = false }
|
||||
}
|
||||
|
||||
private ControlFlowElement getANonExactScopeChild(ControlFlowScope scope) {
|
||||
scope.isNonExact() and
|
||||
result = scope
|
||||
or
|
||||
result = getANonExactScopeChild(scope).getAChild()
|
||||
private newtype TControlFlowElementOrBasicBlock =
|
||||
TControlFlowElement(ControlFlowElement cfe) or
|
||||
TBasicBlock(ControlFlow::BasicBlock bb)
|
||||
|
||||
class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock {
|
||||
ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) }
|
||||
|
||||
ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) }
|
||||
|
||||
string toString() {
|
||||
result = this.asControlFlowElement().toString()
|
||||
or
|
||||
result = this.asBasicBlock().toString()
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
result = this.asControlFlowElement().getLocation()
|
||||
or
|
||||
result = this.asBasicBlock().getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock }
|
||||
|
||||
private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) {
|
||||
c.asControlFlowElement().(ControlFlowScope).isNonExact()
|
||||
}
|
||||
|
||||
private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) {
|
||||
pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement()
|
||||
or
|
||||
pred.asControlFlowElement() = succ.asControlFlowElement().getAChild()
|
||||
}
|
||||
|
||||
private predicate basicBlockInNonExactScope(
|
||||
ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope
|
||||
) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope)
|
||||
|
||||
pragma[noinline]
|
||||
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
|
||||
result.getANode().getAstNode() = getANonExactScopeChild(scope) and
|
||||
basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and
|
||||
exactScope = false
|
||||
or
|
||||
scope.isExact() and
|
||||
|
||||
@@ -6,7 +6,9 @@ private import ControlFlowReachability
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.commons.Collections
|
||||
private import semmle.code.csharp.Conversion
|
||||
private import semmle.code.csharp.exprs.internal.Expr
|
||||
private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.Unification
|
||||
@@ -16,7 +18,6 @@ private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import semmle.code.csharp.frameworks.NHibernate
|
||||
private import semmle.code.csharp.frameworks.Razor
|
||||
private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
private import semmle.code.csharp.internal.Location
|
||||
private import codeql.util.Unit
|
||||
@@ -1087,7 +1088,7 @@ predicate exprMayHavePostUpdateNode(Expr e) {
|
||||
or
|
||||
t = any(TypeParameter tp | not tp.isValueType())
|
||||
or
|
||||
t.isRefLikeType()
|
||||
t instanceof Struct
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2377,6 +2378,16 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
storeStepDelegateCall(node1, c, node2)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isAssignExprLValueDescendant(Expr e) {
|
||||
e = any(AssignExpr ae).getLValue()
|
||||
or
|
||||
exists(Expr parent |
|
||||
isAssignExprLValueDescendant(parent) and
|
||||
e = parent.getAChildExpr()
|
||||
)
|
||||
}
|
||||
|
||||
private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration {
|
||||
ReadStepConfiguration() { this = "ReadStepConfiguration" }
|
||||
|
||||
@@ -2432,7 +2443,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
|
||||
scope =
|
||||
any(AssignExpr ae |
|
||||
ae = defTo.(AssignableDefinitions::TupleAssignmentDefinition).getAssignment() and
|
||||
e = ae.getLValue().getAChildExpr*().(TupleExpr) and
|
||||
isAssignExprLValueDescendant(e.(TupleExpr)) and
|
||||
exactScope = false and
|
||||
isSuccessor = true
|
||||
)
|
||||
@@ -2488,7 +2499,7 @@ private predicate readContentStep(Node node1, Content c, Node node2) {
|
||||
)
|
||||
or
|
||||
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
|
||||
te = any(PatternExpr pe).getAChildExpr*() and
|
||||
isPatternExprDescendant(te) and
|
||||
exists(AssignableDefinitions::LocalVariableDefinition lvd |
|
||||
node2.(AssignableDefinitionNode).getDefinition() = lvd and
|
||||
lvd.getDeclaration() = item and
|
||||
@@ -2545,6 +2556,7 @@ private predicate clearsCont(Node n, Content c) {
|
||||
a.getType() = s and
|
||||
f = s.getAField() and
|
||||
c.(FieldContent).getField() = f.getUnboundDeclaration() and
|
||||
not f.getType() instanceof CollectionType and
|
||||
not f.isRef()
|
||||
)
|
||||
or
|
||||
|
||||
@@ -239,12 +239,25 @@ module ModelValidation {
|
||||
)
|
||||
}
|
||||
|
||||
string getIncorrectConstructorSummaryOutput() {
|
||||
exists(string namespace, string type, string name, string output |
|
||||
type = name or
|
||||
type = name + "<" + any(string s)
|
||||
|
|
||||
summaryModel(namespace, type, _, name, _, _, _, output, _, _, _) and
|
||||
output.matches("ReturnValue%") and
|
||||
result =
|
||||
"Constructor model for " + namespace + "." + type +
|
||||
" should use `Argument[this]` in the output, not `ReturnValue`."
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if some row in a MaD flow model appears to contain typos. */
|
||||
query predicate invalidModelRow(string msg) {
|
||||
msg =
|
||||
[
|
||||
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
|
||||
KindVal::getInvalidModelKind()
|
||||
getIncorrectConstructorSummaryOutput(), KindVal::getInvalidModelKind()
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,16 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
|
||||
}
|
||||
}
|
||||
|
||||
private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) {
|
||||
exists(OperatorCall oc | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, oc, cfn) |
|
||||
oc.getTarget() instanceof ImplicitConversionOperator
|
||||
)
|
||||
}
|
||||
|
||||
private ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) {
|
||||
result = getALastEvalNode(e)
|
||||
}
|
||||
|
||||
private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo)
|
||||
}
|
||||
@@ -177,6 +187,16 @@ private module Cached {
|
||||
readStep(nodeFrom, any(DataFlow::ContentSet c | c.isElement()), nodeTo)
|
||||
or
|
||||
nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false)
|
||||
or
|
||||
// Allow reverse update flow for implicit conversion operator calls.
|
||||
// This is needed to support flow out of method call arguments, where an implicit conversion is applied
|
||||
// to a call argument.
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() =
|
||||
getPostUpdateReverseStep(nodeFrom
|
||||
.(PostUpdateNode)
|
||||
.getPreUpdateNode()
|
||||
.(DataFlow::ExprNode)
|
||||
.getControlFlowNode())
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
|
||||
@@ -15,16 +15,47 @@ private class ControlFlowScope extends ControlFlowElement {
|
||||
predicate isNonExact() { exactScope = false }
|
||||
}
|
||||
|
||||
private ControlFlowElement getANonExactScopeChild(ControlFlowScope scope) {
|
||||
scope.isNonExact() and
|
||||
result = scope
|
||||
or
|
||||
result = getANonExactScopeChild(scope).getAChild()
|
||||
private newtype TControlFlowElementOrBasicBlock =
|
||||
TControlFlowElement(ControlFlowElement cfe) or
|
||||
TBasicBlock(ControlFlow::BasicBlock bb)
|
||||
|
||||
class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock {
|
||||
ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) }
|
||||
|
||||
ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) }
|
||||
|
||||
string toString() {
|
||||
result = this.asControlFlowElement().toString()
|
||||
or
|
||||
result = this.asBasicBlock().toString()
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
result = this.asControlFlowElement().getLocation()
|
||||
or
|
||||
result = this.asBasicBlock().getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock }
|
||||
|
||||
private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) {
|
||||
c.asControlFlowElement().(ControlFlowScope).isNonExact()
|
||||
}
|
||||
|
||||
private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) {
|
||||
pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement()
|
||||
or
|
||||
pred.asControlFlowElement() = succ.asControlFlowElement().getAChild()
|
||||
}
|
||||
|
||||
private predicate basicBlockInNonExactScope(
|
||||
ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope
|
||||
) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope)
|
||||
|
||||
pragma[noinline]
|
||||
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
|
||||
result.getANode().getAstNode() = getANonExactScopeChild(scope) and
|
||||
basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and
|
||||
exactScope = false
|
||||
or
|
||||
scope.isExact() and
|
||||
|
||||
@@ -11,7 +11,7 @@ import Expr
|
||||
* (`LocalVariableDeclAndInitExpr`), a simple assignment (`AssignExpr`), or
|
||||
* an assignment operation (`AssignOperation`).
|
||||
*/
|
||||
class Assignment extends Operation, @assign_expr {
|
||||
class Assignment extends BinaryOperation, @assign_expr {
|
||||
Assignment() {
|
||||
this instanceof LocalVariableDeclExpr
|
||||
implies
|
||||
@@ -20,6 +20,10 @@ class Assignment extends Operation, @assign_expr {
|
||||
expr_parent(_, 0, this)
|
||||
}
|
||||
|
||||
override Expr getLeftOperand() { result = this.getChild(1) }
|
||||
|
||||
override Expr getRightOperand() { result = this.getChild(0) }
|
||||
|
||||
/** Gets the left operand of this assignment. */
|
||||
Expr getLValue() { result = this.getChild(1) }
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import semmle.code.csharp.Type
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.TypeRef
|
||||
private import internal.Expr
|
||||
|
||||
/**
|
||||
* An expression. Either an access (`Access`), a call (`Call`), an object or
|
||||
@@ -64,14 +65,24 @@ class Expr extends ControlFlowElement, @expr {
|
||||
/** Gets the enclosing callable of this expression, if any. */
|
||||
override Callable getEnclosingCallable() { enclosingCallable(this, result) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isExpandedAssignmentRValueDescendant() {
|
||||
this =
|
||||
any(AssignOperation op).getExpandedAssignment().getRValue().getChildExpr(0).getAChildExpr()
|
||||
or
|
||||
exists(Expr parent |
|
||||
parent.isExpandedAssignmentRValueDescendant() and
|
||||
this = parent.getAChildExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression is generated by the compiler and does not appear
|
||||
* explicitly in the source code.
|
||||
*/
|
||||
final predicate isImplicit() {
|
||||
compiler_generated(this) or
|
||||
this =
|
||||
any(AssignOperation op).getExpandedAssignment().getRValue().getChildExpr(0).getAChildExpr+()
|
||||
this.isExpandedAssignmentRValueDescendant()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +244,8 @@ class UnaryOperation extends Operation, @un_op {
|
||||
* A binary operation. Either a binary arithmetic operation
|
||||
* (`BinaryArithmeticOperation`), a binary bitwise operation
|
||||
* (`BinaryBitwiseOperation`), a comparison operation (`ComparisonOperation`),
|
||||
* or a binary logical operation (`BinaryLogicalOperation`).
|
||||
* a binary logical operation (`BinaryLogicalOperation`), or an
|
||||
* assignment (`Assignment`).
|
||||
*/
|
||||
class BinaryOperation extends Operation, @bin_op {
|
||||
/** Gets the left operand of this binary operation. */
|
||||
@@ -1133,7 +1145,7 @@ class TupleExpr extends Expr, @tuple_expr {
|
||||
/** Holds if this expression is a tuple construction. */
|
||||
predicate isConstruction() {
|
||||
not this = getAnAssignOrForeachChild() and
|
||||
not this = any(PatternExpr pe).getAChildExpr*()
|
||||
not isPatternExprDescendant(this)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TupleExpr" }
|
||||
|
||||
11
csharp/ql/lib/semmle/code/csharp/exprs/internal/Expr.qll
Normal file
11
csharp/ql/lib/semmle/code/csharp/exprs/internal/Expr.qll
Normal file
@@ -0,0 +1,11 @@
|
||||
private import csharp
|
||||
|
||||
pragma[nomagic]
|
||||
predicate isPatternExprDescendant(Expr e) {
|
||||
e instanceof PatternExpr
|
||||
or
|
||||
exists(Expr parent |
|
||||
isPatternExprDescendant(parent) and
|
||||
e = parent.getAChildExpr()
|
||||
)
|
||||
}
|
||||
@@ -1261,10 +1261,10 @@ case @expr.kind of
|
||||
@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
|
||||
@comp_expr = @equality_op_expr | @rel_op_expr;
|
||||
|
||||
@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op;
|
||||
@op_expr = @un_op | @bin_op | @ternary_op;
|
||||
|
||||
@ternary_op = @ternary_log_op_expr;
|
||||
@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
|
||||
@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
|
||||
@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
|
||||
| @pointer_indirection_expr | @address_of_expr;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Expand @bin_op union to include @assign_expr
|
||||
compatibility: full
|
||||
@@ -15,23 +15,6 @@
|
||||
|
||||
import csharp
|
||||
|
||||
/** An expression containing a qualified member access, a method call, or an array access. */
|
||||
class DangerousExpression extends Expr {
|
||||
DangerousExpression() {
|
||||
exists(Expr e | this = e.getParent*() |
|
||||
exists(Expr q | q = e.(MemberAccess).getQualifier() |
|
||||
not q instanceof ThisAccess and
|
||||
not q instanceof BaseAccess
|
||||
)
|
||||
or
|
||||
e instanceof MethodCall
|
||||
or
|
||||
e instanceof ArrayAccess
|
||||
) and
|
||||
not exists(Expr e | this = e.getParent*() | e.(Call).getTarget().getAParameter().isOutOrRef())
|
||||
}
|
||||
}
|
||||
|
||||
/** A use of `&` or `|` on operands of type boolean. */
|
||||
class NonShortCircuit extends BinaryBitwiseOperation {
|
||||
NonShortCircuit() {
|
||||
@@ -42,10 +25,40 @@ class NonShortCircuit extends BinaryBitwiseOperation {
|
||||
) and
|
||||
not exists(AssignBitwiseOperation abo | abo.getExpandedAssignment().getRValue() = this) and
|
||||
this.getLeftOperand().getType() instanceof BoolType and
|
||||
this.getRightOperand().getType() instanceof BoolType and
|
||||
this.getRightOperand() instanceof DangerousExpression
|
||||
this.getRightOperand().getType() instanceof BoolType
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasRightOperandDescendant(Expr e) {
|
||||
e = this.getRightOperand()
|
||||
or
|
||||
exists(Expr parent |
|
||||
this.hasRightOperandDescendant(parent) and
|
||||
e.getParent() = parent
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this non-short-circuit expression contains a qualified member access,
|
||||
* a method call, or an array access inside the right operand.
|
||||
*/
|
||||
predicate isDangerous() {
|
||||
exists(Expr e | this.hasRightOperandDescendant(e) |
|
||||
exists(Expr q | q = e.(MemberAccess).getQualifier() |
|
||||
not q instanceof ThisAccess and
|
||||
not q instanceof BaseAccess
|
||||
)
|
||||
or
|
||||
e instanceof MethodCall
|
||||
or
|
||||
e instanceof ArrayAccess
|
||||
) and
|
||||
not exists(Expr e | this.hasRightOperandDescendant(e) |
|
||||
e.(Call).getTarget().getAParameter().isOutOrRef()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from NonShortCircuit e
|
||||
where e.isDangerous()
|
||||
select e, "Potentially dangerous use of non-short circuit logic."
|
||||
|
||||
@@ -321,6 +321,7 @@
|
||||
| CSharp7.cs:283:20:283:62 | call to method Select<KeyValuePair<Int32,String>,(Int32,String)> | CSharp7.cs:283:13:283:16 | access to local variable list |
|
||||
| CSharp7.cs:283:32:283:35 | SSA param(item) | CSharp7.cs:283:41:283:44 | access to parameter item |
|
||||
| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:32:283:35 | SSA param(item) |
|
||||
| CSharp7.cs:283:41:283:44 | [post] access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item |
|
||||
| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:41:283:48 | access to property Key |
|
||||
| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item |
|
||||
| CSharp7.cs:283:51:283:54 | access to parameter item | CSharp7.cs:283:51:283:60 | access to property Value |
|
||||
|
||||
@@ -122,6 +122,16 @@ edges
|
||||
| Constructors.cs:143:29:143:30 | access to local variable o2 : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj2] : Object | provenance | |
|
||||
| Constructors.cs:144:14:144:15 | access to local variable r1 : R1 [property Obj1] : Object | Constructors.cs:144:14:144:20 | access to property Obj1 | provenance | |
|
||||
| Constructors.cs:145:14:145:15 | access to local variable r1 : R1 [property Obj2] : Object | Constructors.cs:145:14:145:20 | access to property Obj2 | provenance | |
|
||||
| Constructors.cs:157:40:157:40 | o : Object | Constructors.cs:157:52:157:52 | access to parameter o : Object | provenance | |
|
||||
| Constructors.cs:157:46:157:48 | [post] this access : CPartial [property Obj] : Object | Constructors.cs:157:24:157:31 | this [Return] : CPartial [property Obj] : Object | provenance | |
|
||||
| Constructors.cs:157:52:157:52 | access to parameter o : Object | Constructors.cs:157:46:157:48 | [post] this access : CPartial [property Obj] : Object | provenance | |
|
||||
| Constructors.cs:162:13:162:13 | access to local variable o : Object | Constructors.cs:163:37:163:37 | access to local variable o : Object | provenance | |
|
||||
| Constructors.cs:162:17:162:34 | call to method Source<Object> : Object | Constructors.cs:162:13:162:13 | access to local variable o : Object | provenance | |
|
||||
| Constructors.cs:163:13:163:20 | access to local variable cPartial : CPartial [property Obj] : Object | Constructors.cs:164:14:164:21 | access to local variable cPartial : CPartial [property Obj] : Object | provenance | |
|
||||
| Constructors.cs:163:24:163:38 | object creation of type CPartial : CPartial [property Obj] : Object | Constructors.cs:163:13:163:20 | access to local variable cPartial : CPartial [property Obj] : Object | provenance | |
|
||||
| Constructors.cs:163:37:163:37 | access to local variable o : Object | Constructors.cs:157:40:157:40 | o : Object | provenance | |
|
||||
| Constructors.cs:163:37:163:37 | access to local variable o : Object | Constructors.cs:163:24:163:38 | object creation of type CPartial : CPartial [property Obj] : Object | provenance | |
|
||||
| Constructors.cs:164:14:164:21 | access to local variable cPartial : CPartial [property Obj] : Object | Constructors.cs:164:14:164:25 | access to property Obj | provenance | |
|
||||
nodes
|
||||
| Constructors.cs:3:18:3:26 | [post] this access : C_no_ctor [field s1] : Object | semmle.label | [post] this access : C_no_ctor [field s1] : Object |
|
||||
| Constructors.cs:5:24:5:25 | [post] this access : C_no_ctor [field s1] : Object | semmle.label | [post] this access : C_no_ctor [field s1] : Object |
|
||||
@@ -255,6 +265,17 @@ nodes
|
||||
| Constructors.cs:144:14:144:20 | access to property Obj1 | semmle.label | access to property Obj1 |
|
||||
| Constructors.cs:145:14:145:15 | access to local variable r1 : R1 [property Obj2] : Object | semmle.label | access to local variable r1 : R1 [property Obj2] : Object |
|
||||
| Constructors.cs:145:14:145:20 | access to property Obj2 | semmle.label | access to property Obj2 |
|
||||
| Constructors.cs:157:24:157:31 | this [Return] : CPartial [property Obj] : Object | semmle.label | this [Return] : CPartial [property Obj] : Object |
|
||||
| Constructors.cs:157:40:157:40 | o : Object | semmle.label | o : Object |
|
||||
| Constructors.cs:157:46:157:48 | [post] this access : CPartial [property Obj] : Object | semmle.label | [post] this access : CPartial [property Obj] : Object |
|
||||
| Constructors.cs:157:52:157:52 | access to parameter o : Object | semmle.label | access to parameter o : Object |
|
||||
| Constructors.cs:162:13:162:13 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| Constructors.cs:162:17:162:34 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
|
||||
| Constructors.cs:163:13:163:20 | access to local variable cPartial : CPartial [property Obj] : Object | semmle.label | access to local variable cPartial : CPartial [property Obj] : Object |
|
||||
| Constructors.cs:163:24:163:38 | object creation of type CPartial : CPartial [property Obj] : Object | semmle.label | object creation of type CPartial : CPartial [property Obj] : Object |
|
||||
| Constructors.cs:163:37:163:37 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| Constructors.cs:164:14:164:21 | access to local variable cPartial : CPartial [property Obj] : Object | semmle.label | access to local variable cPartial : CPartial [property Obj] : Object |
|
||||
| Constructors.cs:164:14:164:25 | access to property Obj | semmle.label | access to property Obj |
|
||||
subpaths
|
||||
| Constructors.cs:44:18:44:19 | this access : C2 [parameter o21param] : Object | Constructors.cs:46:23:46:27 | this access : C2 [parameter o21param] : Object | Constructors.cs:46:23:46:27 | [post] this access : C2 [field Obj21] : Object | Constructors.cs:44:18:44:19 | [post] this access : C2 [field Obj21] : Object |
|
||||
| Constructors.cs:64:37:64:37 | access to parameter o : Object | Constructors.cs:57:54:57:55 | o2 : Object | Constructors.cs:59:13:59:14 | access to parameter o1 : Object | Constructors.cs:64:27:64:34 | access to parameter o22param : Object |
|
||||
@@ -273,6 +294,7 @@ subpaths
|
||||
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:121:38:121:40 | oc2 : Object | Constructors.cs:121:16:121:17 | this [Return] : C4 [property Obj2] : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object |
|
||||
| Constructors.cs:143:25:143:26 | access to local variable o1 : Object | Constructors.cs:137:29:137:32 | Obj1 : Object | Constructors.cs:137:19:137:20 | this [Return] : R1 [property Obj1] : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj1] : Object |
|
||||
| Constructors.cs:143:29:143:30 | access to local variable o2 : Object | Constructors.cs:137:42:137:45 | Obj2 : Object | Constructors.cs:137:19:137:20 | this [Return] : R1 [property Obj2] : Object | Constructors.cs:143:18:143:31 | object creation of type R1 : R1 [property Obj2] : Object |
|
||||
| Constructors.cs:163:37:163:37 | access to local variable o : Object | Constructors.cs:157:40:157:40 | o : Object | Constructors.cs:157:24:157:31 | this [Return] : CPartial [property Obj] : Object | Constructors.cs:163:24:163:38 | object creation of type CPartial : CPartial [property Obj] : Object |
|
||||
testFailures
|
||||
#select
|
||||
| Constructors.cs:15:18:15:19 | access to field s1 | Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | Constructors.cs:15:18:15:19 | access to field s1 | $@ | Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
@@ -288,3 +310,4 @@ testFailures
|
||||
| Constructors.cs:134:14:134:20 | access to property Obj2 | Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | Constructors.cs:134:14:134:20 | access to property Obj2 | $@ | Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
| Constructors.cs:144:14:144:20 | access to property Obj1 | Constructors.cs:141:18:141:34 | call to method Source<Object> : Object | Constructors.cs:144:14:144:20 | access to property Obj1 | $@ | Constructors.cs:141:18:141:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
| Constructors.cs:145:14:145:20 | access to property Obj2 | Constructors.cs:142:18:142:35 | call to method Source<Object> : Object | Constructors.cs:145:14:145:20 | access to property Obj2 | $@ | Constructors.cs:142:18:142:35 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
| Constructors.cs:164:14:164:25 | access to property Obj | Constructors.cs:162:17:162:34 | call to method Source<Object> : Object | Constructors.cs:164:14:164:25 | access to property Obj | $@ | Constructors.cs:162:17:162:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
|
||||
@@ -145,6 +145,25 @@ public class Constructors
|
||||
Sink(r1.Obj2); // $ hasValueFlow=10
|
||||
}
|
||||
|
||||
public partial class CPartial
|
||||
{
|
||||
public object Obj { get; }
|
||||
|
||||
public partial CPartial(object o);
|
||||
}
|
||||
|
||||
public partial class CPartial
|
||||
{
|
||||
public partial CPartial(object o) => Obj = o;
|
||||
}
|
||||
|
||||
public void M8()
|
||||
{
|
||||
var o = Source<object>(11);
|
||||
var cPartial = new CPartial(o);
|
||||
Sink(cPartial.Obj); // $ hasValueFlow=11
|
||||
}
|
||||
|
||||
public static void Sink(object o) { }
|
||||
|
||||
public static T Source<T>(object source) => throw null;
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace My.Qltest
|
||||
|
||||
x = TaggedSrcPropertyGetter;
|
||||
x = this[0];
|
||||
|
||||
S s;
|
||||
StructSrc(s);
|
||||
}
|
||||
|
||||
[SourceAttribute]
|
||||
@@ -65,7 +68,10 @@ namespace My.Qltest
|
||||
|
||||
[SourceAttribute]
|
||||
object this[int i] => null;
|
||||
|
||||
void StructSrc(S s) { }
|
||||
}
|
||||
|
||||
struct S { }
|
||||
class SourceAttribute : System.Attribute { }
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ invalidModelRow
|
||||
| Sources.cs:20:17:20:33 | call to method SrcTwoArg | local |
|
||||
| Sources.cs:22:17:22:39 | access to property TaggedSrcPropertyGetter | local |
|
||||
| Sources.cs:23:17:23:23 | access to indexer | local |
|
||||
| Sources.cs:27:14:27:20 | this | local |
|
||||
| Sources.cs:27:29:27:45 | taggedMethodParam | local |
|
||||
| Sources.cs:31:47:31:60 | taggedSrcParam | local |
|
||||
| Sources.cs:43:45:43:45 | p | local |
|
||||
| Sources.cs:50:50:50:50 | p | local |
|
||||
| Sources.cs:56:16:56:30 | this | local |
|
||||
| Sources.cs:26:23:26:23 | [post] access to local variable s | local |
|
||||
| Sources.cs:30:14:30:20 | this | local |
|
||||
| Sources.cs:30:29:30:45 | taggedMethodParam | local |
|
||||
| Sources.cs:34:47:34:60 | taggedSrcParam | local |
|
||||
| Sources.cs:46:45:46:45 | p | local |
|
||||
| Sources.cs:53:50:53:50 | p | local |
|
||||
| Sources.cs:59:16:59:30 | this | local |
|
||||
|
||||
@@ -19,3 +19,4 @@ extensions:
|
||||
- ["My.Qltest", "SourceAttribute", false, "", "", "Attribute", "", "local", "manual"]
|
||||
- ["My.Qltest", "SourceAttribute", false, "", "", "Attribute.Getter", "ReturnValue", "local", "manual"]
|
||||
- ["My.Qltest", "A", false, "SrcTwoArg", "(System.String,System.String)", "", "ReturnValue", "local", "manual"]
|
||||
- ["My.Qltest", "A", false, "StructSrc", "", "", "Argument[0]", "local", "manual"]
|
||||
|
||||
@@ -44,5 +44,13 @@ namespace RemoteFlowSource
|
||||
{
|
||||
Use(request.Unvalidated.RawUrl);
|
||||
}
|
||||
|
||||
public static async void M3(System.Net.WebSockets.WebSocket webSocket)
|
||||
{
|
||||
var buffer = new byte[1024];
|
||||
var segment = new ArraySegment<byte>(buffer);
|
||||
var result = await webSocket.ReceiveAsync(segment, System.Threading.CancellationToken.None);
|
||||
Use(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
| RemoteFlowSource.cs:40:17:40:23 | access to parameter request | ASP.NET query string |
|
||||
| RemoteFlowSource.cs:45:17:45:23 | access to parameter request | ASP.NET query string |
|
||||
| RemoteFlowSource.cs:45:17:45:42 | access to property RawUrl | ASP.NET unvalidated request data |
|
||||
| RemoteFlowSource.cs:52:55:52:61 | [post] access to local variable segment | external |
|
||||
|
||||
@@ -185,6 +185,10 @@ source
|
||||
| System.IO;StreamWriter;StreamWriter;(System.String,System.IO.FileStreamOptions);Argument[this];file-write;manual |
|
||||
| System.IO;StreamWriter;StreamWriter;(System.String,System.Text.Encoding,System.IO.FileStreamOptions);Argument[this];file-write;manual |
|
||||
| System.Net.Sockets;TcpClient;GetStream;();ReturnValue;remote;manual |
|
||||
| System.Net.WebSockets;ClientWebSocket;ReceiveAsync;(System.ArraySegment<System.Byte>,System.Threading.CancellationToken);Argument[0];remote;manual |
|
||||
| System.Net.WebSockets;ClientWebSocket;ReceiveAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);Argument[0];remote;manual |
|
||||
| System.Net.WebSockets;WebSocket;ReceiveAsync;(System.ArraySegment<System.Byte>,System.Threading.CancellationToken);Argument[0];remote;manual |
|
||||
| System.Net.WebSockets;WebSocket;ReceiveAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);Argument[0];remote;manual |
|
||||
| System;Console;Read;();ReturnValue;stdin;manual |
|
||||
| System;Console;ReadKey;();ReturnValue;stdin;manual |
|
||||
| System;Console;ReadKey;(System.Boolean);ReturnValue;stdin;manual |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
public class TestImplicitConversionOperator
|
||||
{
|
||||
static void Sink(object o) { }
|
||||
static void TaintArgument(ArraySegment<byte> segment) { }
|
||||
|
||||
public void M1()
|
||||
{
|
||||
byte[] bytes = new byte[1];
|
||||
TaintArgument(bytes);
|
||||
Sink(bytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
edges
|
||||
| ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | provenance | |
|
||||
nodes
|
||||
| ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | semmle.label | [post] call to operator implicit conversion : ArraySegment<Byte> |
|
||||
| ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | semmle.label | access to local variable bytes |
|
||||
subpaths
|
||||
#select
|
||||
| ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | $@ | ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | [post] call to operator implicit conversion : ArraySegment<Byte> |
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
import Taint::PathGraph
|
||||
|
||||
module TaintConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodCall mc |
|
||||
mc.getTarget().hasName("TaintArgument") and
|
||||
mc.getAnArgument() = src.(DataFlowPrivate::PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
mc.getTarget().hasName("Sink") and
|
||||
mc.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Taint = TaintTracking::Global<TaintConfig>;
|
||||
|
||||
from Taint::PathNode source, Taint::PathNode sink
|
||||
where Taint::flowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
@@ -0,0 +1,92 @@
|
||||
models
|
||||
edges
|
||||
| structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:18:21:18:37 | call to method Source<Object> : Object | structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:18:21:18:37 | call to method Source<Object> : Object | structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:24:13:24:13 | access to local variable o : Object | structs.cs:25:24:25:24 | access to local variable o : Object | provenance | |
|
||||
| structs.cs:24:13:24:13 | access to local variable o : Object | structs.cs:25:24:25:24 | access to local variable o : Object | provenance | |
|
||||
| structs.cs:24:17:24:33 | call to method Source<Object> : Object | structs.cs:24:13:24:13 | access to local variable o : Object | provenance | |
|
||||
| structs.cs:24:17:24:33 | call to method Source<Object> : Object | structs.cs:24:13:24:13 | access to local variable o : Object | provenance | |
|
||||
| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:25:24:25:24 | access to local variable o : Object | structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:25:24:25:24 | access to local variable o : Object | structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | structs.cs:26:14:26:22 | access to array element | provenance | |
|
||||
| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | structs.cs:26:14:26:22 | access to array element | provenance | |
|
||||
| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | provenance | |
|
||||
| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | provenance | |
|
||||
| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | structs.cs:33:14:33:22 | access to array element | provenance | |
|
||||
| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | structs.cs:33:14:33:22 | access to array element | provenance | |
|
||||
nodes
|
||||
| structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | semmle.label | this [Return] : S [field args, element] : Object |
|
||||
| structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | semmle.label | this [Return] : S [field args, element] : Object |
|
||||
| structs.cs:10:27:10:30 | args : Object[] [element] : Object | semmle.label | args : Object[] [element] : Object |
|
||||
| structs.cs:10:27:10:30 | args : Object[] [element] : Object | semmle.label | args : Object[] [element] : Object |
|
||||
| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | semmle.label | [post] this access : S [field args, element] : Object |
|
||||
| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | semmle.label | [post] this access : S [field args, element] : Object |
|
||||
| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | semmle.label | access to parameter args : Object[] [element] : Object |
|
||||
| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | semmle.label | access to parameter args : Object[] [element] : Object |
|
||||
| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | semmle.label | s [Return] : S [field args, element] : Object |
|
||||
| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | semmle.label | s [Return] : S [field args, element] : Object |
|
||||
| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | semmle.label | [post] access to parameter s : S [field args, element] : Object |
|
||||
| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | semmle.label | [post] access to parameter s : S [field args, element] : Object |
|
||||
| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | semmle.label | [post] access to field args : Object[] [element] : Object |
|
||||
| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | semmle.label | [post] access to field args : Object[] [element] : Object |
|
||||
| structs.cs:18:21:18:37 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
|
||||
| structs.cs:18:21:18:37 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
|
||||
| structs.cs:24:13:24:13 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| structs.cs:24:13:24:13 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| structs.cs:24:17:24:33 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
|
||||
| structs.cs:24:17:24:33 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
|
||||
| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | semmle.label | object creation of type S : S [field args, element] : Object |
|
||||
| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | semmle.label | object creation of type S : S [field args, element] : Object |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | semmle.label | [...] : Object[] [element] : Object |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | semmle.label | [...] : Object[] [element] : Object |
|
||||
| structs.cs:25:24:25:24 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| structs.cs:25:24:25:24 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object |
|
||||
| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object |
|
||||
| structs.cs:26:14:26:22 | access to array element | semmle.label | access to array element |
|
||||
| structs.cs:26:14:26:22 | access to array element | semmle.label | access to array element |
|
||||
| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | semmle.label | [post] access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | semmle.label | [post] access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object |
|
||||
| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object |
|
||||
| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object |
|
||||
| structs.cs:33:14:33:22 | access to array element | semmle.label | access to array element |
|
||||
| structs.cs:33:14:33:22 | access to array element | semmle.label | access to array element |
|
||||
subpaths
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object |
|
||||
| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object |
|
||||
testFailures
|
||||
#select
|
||||
| structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source<Object> : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
| structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source<Object> : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
| structs.cs:33:14:33:22 | access to array element | structs.cs:18:21:18:37 | call to method Source<Object> : Object | structs.cs:33:14:33:22 | access to array element | $@ | structs.cs:18:21:18:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
| structs.cs:33:14:33:22 | access to array element | structs.cs:18:21:18:37 | call to method Source<Object> : Object | structs.cs:33:14:33:22 | access to array element | $@ | structs.cs:18:21:18:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
|
||||
12
csharp/ql/test/library-tests/dataflow/structs/StructFlow.ql
Normal file
12
csharp/ql/test/library-tests/dataflow/structs/StructFlow.ql
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import utils.test.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
import PathGraph
|
||||
|
||||
from PathNode source, PathNode sink
|
||||
where flowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
40
csharp/ql/test/library-tests/dataflow/structs/structs.cs
Normal file
40
csharp/ql/test/library-tests/dataflow/structs/structs.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
public class Test
|
||||
{
|
||||
public struct S
|
||||
{
|
||||
public int field;
|
||||
public object[] args;
|
||||
|
||||
public S(object[] args)
|
||||
{
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTainted(S s)
|
||||
{
|
||||
s.args[0] = Source<object>(2);
|
||||
s.field = Source<int>(3);
|
||||
}
|
||||
|
||||
public void M1()
|
||||
{
|
||||
var o = Source<object>(1);
|
||||
var s = new S([o]);
|
||||
Sink(s.args[0]); // $ hasValueFlow=1
|
||||
}
|
||||
|
||||
public void M2()
|
||||
{
|
||||
var s = new S(new object[1]);
|
||||
SetTainted(s);
|
||||
Sink(s.args[0]); // $ hasValueFlow=2
|
||||
Sink(s.field); // $ no flow.
|
||||
}
|
||||
|
||||
public static void Sink(object o) { }
|
||||
|
||||
static T Source<T>(object source) => throw null;
|
||||
}
|
||||
@@ -270,9 +270,10 @@
|
||||
| ViableCallable.cs:679:17:679:20 | Run3 | ViableCallable.cs:637:21:637:21 | M |
|
||||
| ViableCallable.cs:679:17:679:20 | Run3 | ViableCallable.cs:646:21:646:21 | M |
|
||||
| ViableCallable.cs:679:17:679:20 | Run3 | ViableCallable.cs:648:21:648:21 | M |
|
||||
| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:703:42:703:44 | get_Property |
|
||||
| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:703:63:703:65 | set_Property |
|
||||
| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:705:49:705:51 | get_Item |
|
||||
| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:705:70:705:72 | set_Item |
|
||||
| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:706:51:706:53 | add_Event |
|
||||
| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:706:59:706:64 | remove_Event |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:704:24:704:31 | Partial1 |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:705:42:705:44 | get_Property |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:705:63:705:65 | set_Property |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:707:49:707:51 | get_Item |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:707:70:707:72 | set_Item |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:708:51:708:53 | add_Event |
|
||||
| ViableCallable.cs:711:17:711:20 | Run1 | ViableCallable.cs:708:59:708:64 | remove_Event |
|
||||
|
||||
@@ -518,9 +518,10 @@
|
||||
| ViableCallable.cs:683:9:683:16 | call to method M | C22+TestOverloadResolution2<System.Int32>.M(Int32[]) |
|
||||
| ViableCallable.cs:687:9:687:16 | call to method M | C22+TestOverloadResolution1<System.Int32>.M(List<int>) |
|
||||
| ViableCallable.cs:687:9:687:16 | call to method M | C22+TestOverloadResolution2<System.Int32>.M(List<int>) |
|
||||
| ViableCallable.cs:714:9:714:18 | access to property Property | C23+Partial1.set_Property(object) |
|
||||
| ViableCallable.cs:717:13:717:22 | access to property Property | C23+Partial1.get_Property() |
|
||||
| ViableCallable.cs:720:9:720:12 | access to indexer | C23+Partial1.set_Item(int, object) |
|
||||
| ViableCallable.cs:723:13:723:16 | access to indexer | C23+Partial1.get_Item(int) |
|
||||
| ViableCallable.cs:726:9:726:15 | access to event Event | C23+Partial1.add_Event(EventHandler) |
|
||||
| ViableCallable.cs:729:9:729:15 | access to event Event | C23+Partial1.remove_Event(EventHandler) |
|
||||
| ViableCallable.cs:716:9:716:18 | access to property Property | C23+Partial1.set_Property(object) |
|
||||
| ViableCallable.cs:719:13:719:22 | access to property Property | C23+Partial1.get_Property() |
|
||||
| ViableCallable.cs:722:9:722:12 | access to indexer | C23+Partial1.set_Item(int, object) |
|
||||
| ViableCallable.cs:725:13:725:16 | access to indexer | C23+Partial1.get_Item(int) |
|
||||
| ViableCallable.cs:728:9:728:15 | access to event Event | C23+Partial1.add_Event(EventHandler) |
|
||||
| ViableCallable.cs:731:9:731:15 | access to event Event | C23+Partial1.remove_Event(EventHandler) |
|
||||
| ViableCallable.cs:734:18:734:43 | object creation of type Partial1 | C23+Partial1.Partial1(object) |
|
||||
|
||||
@@ -692,6 +692,7 @@ public class C23
|
||||
{
|
||||
public partial class Partial1
|
||||
{
|
||||
public partial Partial1(object obj);
|
||||
public partial object Property { get; set; }
|
||||
|
||||
public partial object this[int index] { get; set; }
|
||||
@@ -700,6 +701,7 @@ public class C23
|
||||
|
||||
public partial class Partial1
|
||||
{
|
||||
public partial Partial1(object obj) { }
|
||||
public partial object Property { get { return null; } set { } }
|
||||
|
||||
public partial object this[int index] { get { return null; } set { } }
|
||||
@@ -727,5 +729,8 @@ public class C23
|
||||
|
||||
// Viable callable: Partial1.remove_Event
|
||||
p.Event -= (sender, e) => { };
|
||||
|
||||
// Viable callable: Partial1.Partial1(object)
|
||||
var p0 = new Partial1(new object());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
import csharp
|
||||
|
||||
from BinaryOperation e
|
||||
where not e instanceof Assignment
|
||||
select e, e.getAnOperand()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
| Partial.cs:7:18:7:42 | PartialMethodWithoutBody1 | true |
|
||||
| Partial.cs:8:17:8:23 | Method2 | false |
|
||||
| Partial.cs:19:18:19:39 | PartialMethodWithBody1 | true |
|
||||
| Partial.cs:20:27:20:48 | PartialMethodWithBody2 | true |
|
||||
| Partial.cs:24:17:24:23 | Method3 | false |
|
||||
| Partial.cs:46:18:46:42 | PartialMethodWithoutBody2 | true |
|
||||
| Partial.cs:47:17:47:23 | Method4 | false |
|
||||
| Partial.cs:52:17:52:23 | Method5 | false |
|
||||
| Partial.cs:9:18:9:42 | PartialMethodWithoutBody1 | true |
|
||||
| Partial.cs:10:17:10:23 | Method2 | false |
|
||||
| Partial.cs:23:18:23:39 | PartialMethodWithBody1 | true |
|
||||
| Partial.cs:24:27:24:48 | PartialMethodWithBody2 | true |
|
||||
| Partial.cs:28:17:28:23 | Method3 | false |
|
||||
| Partial.cs:50:18:50:42 | PartialMethodWithoutBody2 | true |
|
||||
| Partial.cs:51:17:51:23 | Method4 | false |
|
||||
| Partial.cs:57:17:57:23 | Method5 | false |
|
||||
|
||||
@@ -2,6 +2,8 @@ using System;
|
||||
|
||||
partial class TwoPartClass
|
||||
{
|
||||
// Declaring declaration.
|
||||
public partial TwoPartClass(object obj);
|
||||
partial void PartialMethodWithBody1();
|
||||
public partial object PartialMethodWithBody2(object obj);
|
||||
partial void PartialMethodWithoutBody1();
|
||||
@@ -16,6 +18,8 @@ partial class TwoPartClass
|
||||
|
||||
partial class TwoPartClass
|
||||
{
|
||||
// Implementation declaration.
|
||||
public partial TwoPartClass(object obj) { }
|
||||
partial void PartialMethodWithBody1() { }
|
||||
public partial object PartialMethodWithBody2(object obj)
|
||||
{
|
||||
@@ -49,6 +53,7 @@ partial class OnePartPartialClass
|
||||
|
||||
class NonPartialClass
|
||||
{
|
||||
public NonPartialClass(object obj) { }
|
||||
public void Method5() { }
|
||||
public object Property { get; set; }
|
||||
public object this[int index]
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass |
|
||||
| Partial.cs:7:18:7:42 | PartialMethodWithoutBody1 |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass |
|
||||
| Partial.cs:19:18:19:39 | PartialMethodWithBody1 |
|
||||
| Partial.cs:20:27:20:48 | PartialMethodWithBody2 |
|
||||
| Partial.cs:27:27:27:42 | PartialProperty1 |
|
||||
| Partial.cs:29:9:29:11 | get_PartialProperty1 |
|
||||
| Partial.cs:30:9:30:11 | set_PartialProperty1 |
|
||||
| Partial.cs:34:27:34:30 | Item |
|
||||
| Partial.cs:36:9:36:11 | get_Item |
|
||||
| Partial.cs:37:9:37:11 | set_Item |
|
||||
| Partial.cs:41:39:41:51 | PartialEvent1 |
|
||||
| Partial.cs:41:55:41:57 | add_PartialEvent1 |
|
||||
| Partial.cs:41:63:41:68 | remove_PartialEvent1 |
|
||||
| Partial.cs:44:15:44:33 | OnePartPartialClass |
|
||||
| Partial.cs:46:18:46:42 | PartialMethodWithoutBody2 |
|
||||
| Partial.cs:9:18:9:42 | PartialMethodWithoutBody1 |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass |
|
||||
| Partial.cs:22:20:22:31 | TwoPartClass |
|
||||
| Partial.cs:23:18:23:39 | PartialMethodWithBody1 |
|
||||
| Partial.cs:24:27:24:48 | PartialMethodWithBody2 |
|
||||
| Partial.cs:31:27:31:42 | PartialProperty1 |
|
||||
| Partial.cs:33:9:33:11 | get_PartialProperty1 |
|
||||
| Partial.cs:34:9:34:11 | set_PartialProperty1 |
|
||||
| Partial.cs:38:27:38:30 | Item |
|
||||
| Partial.cs:40:9:40:11 | get_Item |
|
||||
| Partial.cs:41:9:41:11 | set_Item |
|
||||
| Partial.cs:45:39:45:51 | PartialEvent1 |
|
||||
| Partial.cs:45:55:45:57 | add_PartialEvent1 |
|
||||
| Partial.cs:45:63:45:68 | remove_PartialEvent1 |
|
||||
| Partial.cs:48:15:48:33 | OnePartPartialClass |
|
||||
| Partial.cs:50:18:50:42 | PartialMethodWithoutBody2 |
|
||||
| PartialMultipleFiles1.cs:1:22:1:41 | PartialMultipleFiles |
|
||||
| PartialMultipleFiles2.cs:1:22:1:41 | PartialMultipleFiles |
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:3:15:3:26 | <object initializer> |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:7:18:7:42 | PartialMethodWithoutBody1 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:8:17:8:23 | Method2 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:19:18:19:39 | PartialMethodWithBody1 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:20:27:20:48 | PartialMethodWithBody2 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:24:17:24:23 | Method3 |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass | Partial.cs:3:15:3:26 | <object initializer> |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass | Partial.cs:7:18:7:42 | PartialMethodWithoutBody1 |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass | Partial.cs:8:17:8:23 | Method2 |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass | Partial.cs:19:18:19:39 | PartialMethodWithBody1 |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass | Partial.cs:20:27:20:48 | PartialMethodWithBody2 |
|
||||
| Partial.cs:17:15:17:26 | TwoPartClass | Partial.cs:24:17:24:23 | Method3 |
|
||||
| Partial.cs:44:15:44:33 | OnePartPartialClass | Partial.cs:44:15:44:33 | <object initializer> |
|
||||
| Partial.cs:44:15:44:33 | OnePartPartialClass | Partial.cs:46:18:46:42 | PartialMethodWithoutBody2 |
|
||||
| Partial.cs:44:15:44:33 | OnePartPartialClass | Partial.cs:47:17:47:23 | Method4 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:9:18:9:42 | PartialMethodWithoutBody1 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:10:17:10:23 | Method2 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:23:18:23:39 | PartialMethodWithBody1 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:24:27:24:48 | PartialMethodWithBody2 |
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:28:17:28:23 | Method3 |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass | Partial.cs:3:15:3:26 | <object initializer> |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass | Partial.cs:9:18:9:42 | PartialMethodWithoutBody1 |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass | Partial.cs:10:17:10:23 | Method2 |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass | Partial.cs:23:18:23:39 | PartialMethodWithBody1 |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass | Partial.cs:24:27:24:48 | PartialMethodWithBody2 |
|
||||
| Partial.cs:19:15:19:26 | TwoPartClass | Partial.cs:28:17:28:23 | Method3 |
|
||||
| Partial.cs:48:15:48:33 | OnePartPartialClass | Partial.cs:48:15:48:33 | <object initializer> |
|
||||
| Partial.cs:48:15:48:33 | OnePartPartialClass | Partial.cs:50:18:50:42 | PartialMethodWithoutBody2 |
|
||||
| Partial.cs:48:15:48:33 | OnePartPartialClass | Partial.cs:51:17:51:23 | Method4 |
|
||||
| PartialMultipleFiles1.cs:1:22:1:41 | PartialMultipleFiles | PartialMultipleFiles1.cs:1:22:1:41 | <object initializer> |
|
||||
| PartialMultipleFiles2.cs:1:22:1:41 | PartialMultipleFiles | PartialMultipleFiles1.cs:1:22:1:41 | <object initializer> |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
| Partial.cs:29:9:29:11 | get_PartialProperty1 | true |
|
||||
| Partial.cs:30:9:30:11 | set_PartialProperty1 | true |
|
||||
| Partial.cs:36:9:36:11 | get_Item | true |
|
||||
| Partial.cs:37:9:37:11 | set_Item | true |
|
||||
| Partial.cs:41:55:41:57 | add_PartialEvent1 | true |
|
||||
| Partial.cs:41:63:41:68 | remove_PartialEvent1 | true |
|
||||
| Partial.cs:53:30:53:32 | get_Property | false |
|
||||
| Partial.cs:53:35:53:37 | set_Property | false |
|
||||
| Partial.cs:56:9:56:11 | get_Item | false |
|
||||
| Partial.cs:57:9:57:11 | set_Item | false |
|
||||
| Partial.cs:59:31:59:35 | add_Event | false |
|
||||
| Partial.cs:59:31:59:35 | remove_Event | false |
|
||||
| Partial.cs:33:9:33:11 | get_PartialProperty1 | true |
|
||||
| Partial.cs:34:9:34:11 | set_PartialProperty1 | true |
|
||||
| Partial.cs:40:9:40:11 | get_Item | true |
|
||||
| Partial.cs:41:9:41:11 | set_Item | true |
|
||||
| Partial.cs:45:55:45:57 | add_PartialEvent1 | true |
|
||||
| Partial.cs:45:63:45:68 | remove_PartialEvent1 | true |
|
||||
| Partial.cs:58:30:58:32 | get_Property | false |
|
||||
| Partial.cs:58:35:58:37 | set_Property | false |
|
||||
| Partial.cs:61:9:61:11 | get_Item | false |
|
||||
| Partial.cs:62:9:62:11 | set_Item | false |
|
||||
| Partial.cs:64:31:64:35 | add_Event | false |
|
||||
| Partial.cs:64:31:64:35 | remove_Event | false |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:3:15:3:26 | {...} |
|
||||
| Partial.cs:44:15:44:33 | OnePartPartialClass | Partial.cs:44:15:44:33 | {...} |
|
||||
| Partial.cs:50:7:50:21 | NonPartialClass | Partial.cs:50:7:50:21 | {...} |
|
||||
| Partial.cs:22:20:22:31 | TwoPartClass | Partial.cs:22:45:22:47 | {...} |
|
||||
| Partial.cs:48:15:48:33 | OnePartPartialClass | Partial.cs:48:15:48:33 | {...} |
|
||||
| Partial.cs:56:12:56:26 | NonPartialClass | Partial.cs:56:40:56:42 | {...} |
|
||||
| PartialMultipleFiles1.cs:1:22:1:41 | PartialMultipleFiles | PartialMultipleFiles1.cs:1:22:1:41 | {...} |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| Partial.cs:41:39:41:51 | PartialEvent1 | true |
|
||||
| Partial.cs:59:31:59:35 | Event | false |
|
||||
| Partial.cs:45:39:45:51 | PartialEvent1 | true |
|
||||
| Partial.cs:64:31:64:35 | Event | false |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| Partial.cs:34:27:34:30 | Item | true |
|
||||
| Partial.cs:54:19:54:22 | Item | false |
|
||||
| Partial.cs:38:27:38:30 | Item | true |
|
||||
| Partial.cs:59:19:59:22 | Item | false |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| Partial.cs:7:18:7:42 | PartialMethodWithoutBody1 | false | 0 |
|
||||
| Partial.cs:19:18:19:39 | PartialMethodWithBody1 | true | 1 |
|
||||
| Partial.cs:20:27:20:48 | PartialMethodWithBody2 | true | 1 |
|
||||
| Partial.cs:46:18:46:42 | PartialMethodWithoutBody2 | false | 0 |
|
||||
| Partial.cs:9:18:9:42 | PartialMethodWithoutBody1 | false | 0 |
|
||||
| Partial.cs:23:18:23:39 | PartialMethodWithBody1 | true | 1 |
|
||||
| Partial.cs:24:27:24:48 | PartialMethodWithBody2 | true | 1 |
|
||||
| Partial.cs:50:18:50:42 | PartialMethodWithoutBody2 | false | 0 |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| Partial.cs:27:27:27:42 | PartialProperty1 | true |
|
||||
| Partial.cs:53:19:53:26 | Property | false |
|
||||
| Partial.cs:31:27:31:42 | PartialProperty1 | true |
|
||||
| Partial.cs:58:19:58:26 | Property | false |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user