Merge branch 'main' of https://github.com/github/codeql into oscarsj/merge-back-rc-3.21

This commit is contained in:
Óscar San José
2026-03-06 16:20:36 +01:00
846 changed files with 87321 additions and 58588 deletions

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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()
}

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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)
}
/**

View File

@@ -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

View File

@@ -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. */

View File

@@ -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

View File

@@ -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

View File

@@ -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. */

View File

@@ -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 |

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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)
)
}

View File

@@ -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

View File

@@ -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))
)

View File

@@ -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()
}

View File

@@ -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()

View File

@@ -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
}
};

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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"

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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>
}

View File

@@ -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>
}

View File

@@ -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"
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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,,,,,,,,,,,,,,,
1 package sink source summary sink:code-injection sink:encryption-decryptor sink:encryption-encryptor sink:encryption-keyprop sink:encryption-symmetrickey sink:file-content-store sink:html-injection sink:js-injection sink:log-injection sink:sql-injection source:commandargs source:database source:environment source:file source:file-write source:remote source:stdin source:windows-registry summary:taint summary:value
44 Newtonsoft.Json 91 73 18
45 ServiceStack 194 7 27 75 92 7
46 SourceGenerators 5 5
47 System 59 47 48 12495 6 5 12 4 1 31 2 6 15 17 4 5 3 6382 6113
48 Windows.Security.Cryptography.Core 1 1

View File

@@ -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

View File

@@ -0,0 +1,2 @@
description: Remove inclusion of @assign_expr in @bin_op
compatibility: full

View File

@@ -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");
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C# 14: Added support for partial constructors.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added reverse taint flow from implicit conversion operator calls to their arguments.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added `System.Net.WebSockets::ReceiveAsync` as a remote flow source.

View File

@@ -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.

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/csharp-all
extensible: sourceModel
data:
- ["System.Net.WebSockets", "WebSocket", True, "ReceiveAsync", "", "", "Argument[0]", "remote", "manual"]

View File

@@ -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?`. */

View File

@@ -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) }
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()
]
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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) }

View File

@@ -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" }

View 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()
)
}

View File

@@ -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

View File

@@ -0,0 +1,2 @@
description: Expand @bin_op union to include @assign_expr
compatibility: full

View File

@@ -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."

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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;

View File

@@ -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 { }
}

View File

@@ -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 |

View File

@@ -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"]

View File

@@ -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);
}
}
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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);
}
}

View File

@@ -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> |

View File

@@ -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()

View File

@@ -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 |

View 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()

View 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;
}

View File

@@ -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 |

View File

@@ -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) |

View File

@@ -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());
}
}

View File

@@ -5,4 +5,5 @@
import csharp
from BinaryOperation e
where not e instanceof Assignment
select e, e.getAnOperand()

View File

@@ -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 |

View File

@@ -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]

View File

@@ -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 |

View File

@@ -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> |

View File

@@ -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 |

View File

@@ -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 | {...} |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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