mirror of
https://github.com/github/codeql.git
synced 2026-04-24 16:25:15 +02:00
Merge branch 'main' into enable-sound-ir
This commit is contained in:
3
.github/workflows/swift.yml
vendored
3
.github/workflows/swift.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "shared/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/**
|
||||
@@ -22,10 +23,12 @@ on:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "shared/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
- .pre-commit-config.yaml
|
||||
- "!**/*.md"
|
||||
- "!**/*.qhelp"
|
||||
branches:
|
||||
|
||||
@@ -364,6 +364,8 @@ class ConversionNode extends ExprNode {
|
||||
childIndex = 0 and
|
||||
result.getAst() = conv.getExpr() and
|
||||
conv.getExpr() instanceof Conversion
|
||||
or
|
||||
result.getAst() = expr.getImplicitDestructorCall(childIndex - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -286,6 +286,10 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
predicate knownSourceModel(Node source, string model) { none() }
|
||||
|
||||
predicate knownSinkModel(Node sink, string model) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
|
||||
* side-effect, resulting in a summary from `p` to itself.
|
||||
|
||||
@@ -516,7 +516,7 @@ private module ThisFlow {
|
||||
*/
|
||||
cached
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
simpleLocalFlowStep(nodeFrom, nodeTo)
|
||||
simpleLocalFlowStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// Field flow is not strictly a "step" but covers the whole function
|
||||
// transitively. There's no way to get a step-like relation out of the global
|
||||
@@ -530,64 +530,67 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
* This is the local flow predicate that's used as a building block in global
|
||||
* data flow. It may have less flow than the `localFlowStep` predicate.
|
||||
*/
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Expr -> Expr
|
||||
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
// Assignment -> LValue post-update node
|
||||
//
|
||||
// This is used for assignments whose left-hand side is not a variable
|
||||
// assignment or a storeStep but is still modeled by other means. It could be
|
||||
// a call to `operator*` or `operator[]` where taint should flow to the
|
||||
// post-update node of the qualifier.
|
||||
exists(AssignExpr assign |
|
||||
nodeFrom.asExpr() = assign and
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
|
||||
)
|
||||
or
|
||||
// Node -> FlowVar -> VariableAccess
|
||||
exists(FlowVar var |
|
||||
(
|
||||
exprToVarStep(nodeFrom.asExpr(), var)
|
||||
or
|
||||
varSourceBaseCase(var, nodeFrom.asParameter())
|
||||
or
|
||||
varSourceBaseCase(var, nodeFrom.asUninitialized())
|
||||
or
|
||||
var.definedPartiallyAt(nodeFrom.asPartialDefinition())
|
||||
) and
|
||||
varToNodeStep(var, nodeTo)
|
||||
)
|
||||
or
|
||||
// Expr -> DefinitionByReferenceNode
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
// `this` -> adjacent-`this`
|
||||
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
|
||||
or
|
||||
// post-update-`this` -> following-`this`-ref
|
||||
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
|
||||
or
|
||||
// In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`,
|
||||
// from which there is field flow to `x` via reverse read.
|
||||
exists(PartialDefinition def, Expr inner, Expr outer |
|
||||
def.definesExpressions(inner, outer) and
|
||||
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
|
||||
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
or
|
||||
// Reverse flow: data that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows data to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasDataFlow(inModel, outModel) and
|
||||
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
|
||||
(
|
||||
// Expr -> Expr
|
||||
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
// Assignment -> LValue post-update node
|
||||
//
|
||||
// This is used for assignments whose left-hand side is not a variable
|
||||
// assignment or a storeStep but is still modeled by other means. It could be
|
||||
// a call to `operator*` or `operator[]` where taint should flow to the
|
||||
// post-update node of the qualifier.
|
||||
exists(AssignExpr assign |
|
||||
nodeFrom.asExpr() = assign and
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
|
||||
)
|
||||
or
|
||||
// Node -> FlowVar -> VariableAccess
|
||||
exists(FlowVar var |
|
||||
(
|
||||
exprToVarStep(nodeFrom.asExpr(), var)
|
||||
or
|
||||
varSourceBaseCase(var, nodeFrom.asParameter())
|
||||
or
|
||||
varSourceBaseCase(var, nodeFrom.asUninitialized())
|
||||
or
|
||||
var.definedPartiallyAt(nodeFrom.asPartialDefinition())
|
||||
) and
|
||||
varToNodeStep(var, nodeTo)
|
||||
)
|
||||
or
|
||||
// Expr -> DefinitionByReferenceNode
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
// `this` -> adjacent-`this`
|
||||
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
|
||||
or
|
||||
// post-update-`this` -> following-`this`-ref
|
||||
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
|
||||
or
|
||||
// In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`,
|
||||
// from which there is field flow to `x` via reverse read.
|
||||
exists(PartialDefinition def, Expr inner, Expr outer |
|
||||
def.definesExpressions(inner, outer) and
|
||||
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
|
||||
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
or
|
||||
// Reverse flow: data that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows data to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasDataFlow(inModel, outModel) and
|
||||
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,8 +32,8 @@ predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
* Holds if the additional step from `src` to `sink` should be included in all
|
||||
* global taint flow configurations.
|
||||
*/
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintStep(src, sink)
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
|
||||
localAdditionalTaintStep(src, sink) and model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,6 +63,12 @@ class Expr extends StmtParent, @expr {
|
||||
* order of destruction.
|
||||
*/
|
||||
DestructorCall getImplicitDestructorCall(int n) {
|
||||
exists(Expr e |
|
||||
e = this.(TemporaryObjectExpr).getExpr() and
|
||||
synthetic_destructor_call(e, max(int i | synthetic_destructor_call(e, i, _)) - n, result)
|
||||
)
|
||||
or
|
||||
not this = any(TemporaryObjectExpr temp).getExpr() and
|
||||
synthetic_destructor_call(this, max(int i | synthetic_destructor_call(this, i, _)) - n, result)
|
||||
}
|
||||
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
|
||||
@@ -1020,6 +1020,10 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
predicate knownSourceModel(Node source, string model) { none() }
|
||||
|
||||
predicate knownSinkModel(Node sink, string model) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
|
||||
* side-effect, resulting in a summary from `p` to itself.
|
||||
@@ -1096,7 +1100,7 @@ private predicate localFlowStepWithSummaries(Node node1, Node node2) {
|
||||
or
|
||||
readStep(node1, _, node2)
|
||||
or
|
||||
DataFlowImplCommon::argumentValueFlowsThrough(node1, _, node2)
|
||||
DataFlowImplCommon::argumentValueFlowsThrough(node1, _, node2, _)
|
||||
}
|
||||
|
||||
/** Holds if `node` flows to a node that is used in a `SwitchInstruction`. */
|
||||
|
||||
@@ -1892,7 +1892,7 @@ private module Cached {
|
||||
* (intra-procedural) step.
|
||||
*/
|
||||
cached
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo, _) }
|
||||
|
||||
private predicate indirectionOperandFlow(RawIndirectOperand nodeFrom, Node nodeTo) {
|
||||
nodeFrom != nodeTo and
|
||||
@@ -1962,41 +1962,45 @@ private module Cached {
|
||||
* data flow. It may have less flow than the `localFlowStep` predicate.
|
||||
*/
|
||||
cached
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Post update node -> Node flow
|
||||
Ssa::postUpdateFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Def-use/Use-use flow
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Operand -> Instruction flow
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
or
|
||||
// Instruction -> Operand flow
|
||||
exists(Instruction iFrom, Operand opTo |
|
||||
iFrom = nodeFrom.asInstruction() and opTo = nodeTo.asOperand()
|
||||
|
|
||||
simpleOperandLocalFlowStep(iFrom, opTo) and
|
||||
// Omit when the instruction node also represents the operand.
|
||||
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
|
||||
)
|
||||
or
|
||||
// Phi node -> Node flow
|
||||
Ssa::fromPhiNode(nodeFrom, nodeTo)
|
||||
or
|
||||
// Indirect operand -> (indirect) instruction flow
|
||||
indirectionOperandFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Indirect instruction -> indirect operand flow
|
||||
indirectionInstructionFlow(nodeFrom, nodeTo)
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
|
||||
(
|
||||
// Post update node -> Node flow
|
||||
Ssa::postUpdateFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Def-use/Use-use flow
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Operand -> Instruction flow
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
or
|
||||
// Instruction -> Operand flow
|
||||
exists(Instruction iFrom, Operand opTo |
|
||||
iFrom = nodeFrom.asInstruction() and opTo = nodeTo.asOperand()
|
||||
|
|
||||
simpleOperandLocalFlowStep(iFrom, opTo) and
|
||||
// Omit when the instruction node also represents the operand.
|
||||
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
|
||||
)
|
||||
or
|
||||
// Phi node -> Node flow
|
||||
Ssa::fromPhiNode(nodeFrom, nodeTo)
|
||||
or
|
||||
// Indirect operand -> (indirect) instruction flow
|
||||
indirectionOperandFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Indirect instruction -> indirect operand flow
|
||||
indirectionInstructionFlow(nodeFrom, nodeTo)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
// Flow through modeled functions
|
||||
modelFlow(nodeFrom, nodeTo)
|
||||
modelFlow(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Reverse flow: data that flows from the definition node back into the indirection returned
|
||||
// by a function. This allows data to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
reverseFlow(nodeFrom, nodeTo)
|
||||
reverseFlow(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {
|
||||
@@ -2011,12 +2015,13 @@ private module Cached {
|
||||
opTo.getDef() = iFrom
|
||||
}
|
||||
|
||||
private predicate modelFlow(Node nodeFrom, Node nodeTo) {
|
||||
private predicate modelFlow(Node nodeFrom, Node nodeTo, string model) {
|
||||
exists(
|
||||
CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut
|
||||
|
|
||||
call.getStaticCallTarget() = func and
|
||||
func.hasDataFlow(modelIn, modelOut)
|
||||
func.hasDataFlow(modelIn, modelOut) and
|
||||
model = "DataFlowFunction"
|
||||
|
|
||||
nodeFrom = callInput(call, modelIn) and
|
||||
nodeTo = callOutput(call, modelOut)
|
||||
|
||||
@@ -10,7 +10,7 @@ private import PrintIRUtilities
|
||||
*/
|
||||
private string getFromFlow(Node node2, int order1, int order2) {
|
||||
exists(Node node1 |
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
simpleLocalFlowStep(node1, node2, _) and
|
||||
result = nodeId(node1, order1, order2)
|
||||
)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ private string getFromFlow(Node node2, int order1, int order2) {
|
||||
*/
|
||||
private string getToFlow(Node node1, int order1, int order2) {
|
||||
exists(Node node2 |
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
simpleLocalFlowStep(node1, node2, _) and
|
||||
result = nodeId(node2, order1, order2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo)
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,10 +24,11 @@ predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo)
|
||||
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`
|
||||
@@ -35,15 +36,18 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
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)
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
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 = ""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,8 +124,8 @@ predicate localExprTaint(Expr e1, Expr e2) {
|
||||
* Holds if the additional step from `src` to `sink` should be included in all
|
||||
* global taint flow configurations.
|
||||
*/
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintStep(src, sink)
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
|
||||
localAdditionalTaintStep(src, sink, model)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +145,7 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
* Holds if taint can flow from `nodeIn` to `nodeOut` through a call to a
|
||||
* modeled function.
|
||||
*/
|
||||
predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
|
||||
predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string model) {
|
||||
// Normal taint steps
|
||||
exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut |
|
||||
call.getStaticCallTarget() = func and
|
||||
@@ -150,7 +154,8 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
|
||||
nodeIn = callInput(call, modelIn) and nodeOut = callOutput(call, modelOut)
|
||||
or
|
||||
exists(int d | nodeIn = callInput(call, modelIn, d) and nodeOut = callOutput(call, modelOut, d))
|
||||
)
|
||||
) and
|
||||
model = "TaintFunction"
|
||||
or
|
||||
// Taint flow from one argument to another and data flow from an argument to a
|
||||
// return value. This happens in functions like `strcat` and `memcpy`. We
|
||||
@@ -167,7 +172,8 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
|
||||
func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and
|
||||
func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and
|
||||
modelMidOut.isParameterDeref(indexMid) and
|
||||
modelMidIn.isParameter(indexMid)
|
||||
modelMidIn.isParameter(indexMid) and
|
||||
model = "TaintFunction"
|
||||
)
|
||||
or
|
||||
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
|
||||
@@ -180,9 +186,11 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
|
||||
indirectArgument.hasAddressOperandAndIndirectionIndex(nodeIn.asOperand(), _) and
|
||||
call.getStaticCallTarget() = func and
|
||||
(
|
||||
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
|
||||
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut) and
|
||||
model = "DataFlowFunction"
|
||||
or
|
||||
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
|
||||
func.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
|
||||
model = "TaintFunction"
|
||||
) and
|
||||
nodeOut = callOutput(call, modelOut)
|
||||
)
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -128,8 +128,10 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
|
||||
)
|
||||
or
|
||||
// suppress destructors of temporary variables until proper support is added for them.
|
||||
exists(Expr parent | parent.getAnImplicitDestructorCall() = expr)
|
||||
// Do not translate implicit destructor calls for unnamed temporary variables that are
|
||||
// conditionally constructed (until we have a mechanism for calling these only when the
|
||||
// temporary's constructor was run)
|
||||
isConditionalTemporaryDestructorCall(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,6 +257,42 @@ private predicate usedAsCondition(Expr expr) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasThrowingChild(Expr e) {
|
||||
e = any(ThrowExpr throw).getFullyConverted()
|
||||
or
|
||||
exists(Expr child |
|
||||
e = getRealParent(child) and
|
||||
hasThrowingChild(child)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isInConditionalEvaluation(Expr e) {
|
||||
exists(ConditionalExpr cond |
|
||||
e = cond.getThen().getFullyConverted() and not cond.isTwoOperand()
|
||||
or
|
||||
e = cond.getElse().getFullyConverted()
|
||||
or
|
||||
// If one of the operands throws then the temporaries constructed in either
|
||||
// branch will also be attached to the ternary expression. We suppress
|
||||
// those destructor calls as well.
|
||||
hasThrowingChild([cond.getThen(), cond.getElse()]) and
|
||||
e = cond.getFullyConverted()
|
||||
)
|
||||
or
|
||||
e = any(LogicalAndExpr lae).getRightOperand().getFullyConverted()
|
||||
or
|
||||
e = any(LogicalOrExpr loe).getRightOperand().getFullyConverted()
|
||||
or
|
||||
isInConditionalEvaluation(getRealParent(e))
|
||||
}
|
||||
|
||||
private predicate isConditionalTemporaryDestructorCall(DestructorCall dc) {
|
||||
exists(TemporaryObjectExpr temp |
|
||||
temp = dc.getQualifier().(ReuseExpr).getReusedExpr() and
|
||||
isInConditionalEvaluation(temp)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `conv` is an `InheritanceConversion` that requires a `TranslatedLoad`, despite not being
|
||||
* marked as having an lvalue-to-rvalue conversion.
|
||||
@@ -782,6 +820,16 @@ newtype TTranslatedElement =
|
||||
not ignoreSideEffects(expr) and
|
||||
opcode = getCallSideEffectOpcode(expr)
|
||||
} or
|
||||
// The set of destructors to invoke after a `throw`. These need to be special
|
||||
// cased because the edge kind following a throw is an `ExceptionEdge`, and
|
||||
// we need to make sure that the edge kind is still an `ExceptionEdge` after
|
||||
// all the destructors have run.
|
||||
TTranslatedDestructorsAfterThrow(ThrowExpr throw) {
|
||||
exists(DestructorCall dc |
|
||||
dc = throw.getAnImplicitDestructorCall() and
|
||||
not ignoreExpr(dc)
|
||||
)
|
||||
} or
|
||||
// A precise side effect of an argument to a `Call`
|
||||
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
|
||||
not ignoreExpr(expr) and
|
||||
|
||||
@@ -90,10 +90,26 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
final override TranslatedElement getChild(int id) {
|
||||
result = this.getChildInternal(id)
|
||||
or
|
||||
exists(int maxChildId, int destructorIndex |
|
||||
maxChildId = max(int childId | exists(this.getChildInternal(childId))) and
|
||||
result.(TranslatedExpr).getExpr() = expr.getImplicitDestructorCall(destructorIndex) and
|
||||
id = maxChildId + 1 + destructorIndex
|
||||
exists(int destructorIndex |
|
||||
result = this.getImplicitDestructorCall(destructorIndex) and
|
||||
id = this.getFirstDestructorCallIndex() + destructorIndex
|
||||
)
|
||||
}
|
||||
|
||||
final private TranslatedExpr getImplicitDestructorCall(int index) {
|
||||
result.getExpr() = expr.getImplicitDestructorCall(index)
|
||||
}
|
||||
|
||||
final override predicate hasAnImplicitDestructorCall() {
|
||||
exists(this.getImplicitDestructorCall(_))
|
||||
}
|
||||
|
||||
final override int getFirstDestructorCallIndex() {
|
||||
not this.handlesDestructorsExplicitly() and
|
||||
(
|
||||
result = max(int childId | exists(this.getChildInternal(childId))) + 1
|
||||
or
|
||||
not exists(this.getChildInternal(_)) and result = 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -395,6 +411,14 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad
|
||||
result = this.getOperand().getResult()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate handlesDestructorsExplicitly() {
|
||||
// The class that generates IR for `e` will (implicitly or explicitly)
|
||||
// handle the generation of destructor calls for `e`. Without disabling
|
||||
// destructor call generation here the destructor will get multiple
|
||||
// parents.
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1999,6 +2023,13 @@ abstract class TranslatedAllocationSize extends TranslatedExpr, TTranslatedAlloc
|
||||
final override predicate producesExprResult() { none() }
|
||||
|
||||
final override Instruction getResult() { result = this.getInstruction(AllocationSizeTag()) }
|
||||
|
||||
final override predicate handlesDestructorsExplicitly() {
|
||||
// Since the enclosing `TranslatedNewOrNewArrayExpr` (implicitly) handles the destructors
|
||||
// we need to disable the implicit handling here as otherwise the destructors will have
|
||||
// multiple parents
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
|
||||
@@ -2156,6 +2187,13 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
|
||||
|
||||
final override predicate producesExprResult() { none() }
|
||||
|
||||
final override predicate handlesDestructorsExplicitly() {
|
||||
// Since the enclosing `TranslatedNewOrNewArrayExpr` (implicitly) handles the destructors
|
||||
// we need to disable the implicit handling here as otherwise the destructors will have
|
||||
// multiple parents
|
||||
any()
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = expr.getAllocator()
|
||||
}
|
||||
@@ -2817,6 +2855,68 @@ class TranslatedReuseExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the destructor calls of the parent `TranslatedThrow`.
|
||||
*
|
||||
* This object does not itself generate the destructor calls. Instead, its
|
||||
* children provide the actual calls, and this object ensures that we correctly
|
||||
* exit with an `ExceptionEdge` after executing all the destructor calls.
|
||||
*/
|
||||
class TranslatedDestructorsAfterThrow extends TranslatedElement, TTranslatedDestructorsAfterThrow {
|
||||
ThrowExpr throw;
|
||||
|
||||
TranslatedDestructorsAfterThrow() { this = TTranslatedDestructorsAfterThrow(throw) }
|
||||
|
||||
override string toString() { result = "Destructor calls after throw: " + throw }
|
||||
|
||||
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
|
||||
result.getExpr() = throw.getImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getChild(0).getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override ThrowExpr getAst() { result = throw }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = this.getTranslatedImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override Declaration getFunction() { result = throw.getEnclosingFunction() }
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
exists(int id | child = this.getChild(id) |
|
||||
// Transition to the next child, if any.
|
||||
result = this.getChild(id + 1).getFirstInstruction(kind)
|
||||
or
|
||||
// And otherwise, exit this element with an exceptional edge
|
||||
not exists(this.getChild(id + 1)) and
|
||||
kind instanceof ExceptionEdge and
|
||||
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedElement getLastChild() {
|
||||
result =
|
||||
this.getTranslatedImplicitDestructorCall(max(int id |
|
||||
exists(throw.getImplicitDestructorCall(id))
|
||||
))
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getLastChild().getALastInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IR translation of a `throw` expression.
|
||||
*/
|
||||
@@ -2831,13 +2931,22 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = ThrowTag() and
|
||||
kind instanceof ExceptionEdge and
|
||||
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
|
||||
(
|
||||
result = this.getDestructors().getFirstInstruction(kind)
|
||||
or
|
||||
not exists(this.getDestructors()) and
|
||||
kind instanceof ExceptionEdge and
|
||||
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getResult() { none() }
|
||||
|
||||
abstract Opcode getThrowOpcode();
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
TranslatedDestructorsAfterThrow getDestructors() { result.getAst() = expr }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2849,6 +2958,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
|
||||
|
||||
final override TranslatedElement getChildInternal(int id) {
|
||||
result = TranslatedVariableInitialization.super.getChildInternal(id)
|
||||
or
|
||||
id = max(int i | exists(TranslatedVariableInitialization.super.getChildInternal(i))) + 1 and
|
||||
result = this.getDestructors()
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessorInternal(TranslatedElement elem, EdgeKind kind) {
|
||||
@@ -2914,14 +3026,22 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
|
||||
class TranslatedReThrowExpr extends TranslatedThrowExpr {
|
||||
override ReThrowExpr expr;
|
||||
|
||||
override TranslatedElement getChildInternal(int id) { none() }
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and
|
||||
result = this.getDestructors()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(ThrowTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() { result = this.getInstruction(ThrowTag()) }
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getDestructors().getALastInstruction()
|
||||
or
|
||||
not this.hasAnImplicitDestructorCall() and
|
||||
result = this.getInstruction(ThrowTag())
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
|
||||
|
||||
|
||||
@@ -14,5 +14,10 @@ predicate hasDuplicateFunctionEntryPointLocation(Function func) {
|
||||
|
||||
predicate hasDuplicateFunctionEntryPoint(Function func) { count(func.getEntryPoint()) > 1 }
|
||||
|
||||
select count(Function f | hasDuplicateFunctionEntryPoint(f) | f) as duplicateFunctionEntryPoint,
|
||||
count(Function f | hasDuplicateFunctionEntryPointLocation(f) | f) as duplicateFunctionEntryPointLocation
|
||||
predicate hasDuplicateDeclarationEntry(DeclStmt stmt, int i) {
|
||||
strictcount(stmt.getDeclarationEntry(i)) > 1
|
||||
}
|
||||
|
||||
select count(Function f | hasDuplicateFunctionEntryPoint(f)) as duplicateFunctionEntryPoint,
|
||||
count(Function f | hasDuplicateFunctionEntryPointLocation(f)) as duplicateFunctionEntryPointLocation,
|
||||
count(DeclStmt stmt, int i | hasDuplicateDeclarationEntry(stmt, i)) as duplicateDeclarationEntry
|
||||
|
||||
@@ -35,7 +35,7 @@ module XxeConfig implements DataFlow::StateConfigSig {
|
||||
) {
|
||||
// create additional flow steps for `XxeFlowStateTransformer`s
|
||||
state2 = node2.asIndirectExpr().(XxeFlowStateTransformer).transform(state1) and
|
||||
DataFlow::simpleLocalFlowStep(node1, node2)
|
||||
DataFlow::simpleLocalFlowStep(node1, node2, _)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState flowstate) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
|
||||
| test.cpp:689:17:689:29 | temporary object | This object is destroyed before $@ is called. | test.cpp:689:31:689:35 | call to begin | call to begin |
|
||||
| test.cpp:689:46:689:58 | temporary object | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
|
||||
| test.cpp:716:36:716:48 | temporary object | This object is destroyed before $@ is called. | test.cpp:716:17:716:17 | call to begin | call to begin |
|
||||
| test.cpp:716:36:716:48 | temporary object | This object is destroyed before $@ is called. | test.cpp:716:17:716:17 | call to end | call to end |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |
|
||||
|
||||
@@ -677,10 +677,10 @@ std::vector<std::vector<int>> return_self_by_value(const std::vector<std::vector
|
||||
|
||||
void test() {
|
||||
for (auto x : returnValue()) {} // GOOD
|
||||
for (auto x : returnValue()[0]) {} // BAD [NOT DETECTED] (see *)
|
||||
for (auto x : returnValue()[0]) {} // BAD
|
||||
for (auto x : external_by_value(returnValue())) {} // GOOD
|
||||
for (auto x : external_by_const_ref(returnValue())) {} // GOOD
|
||||
for (auto x : returnValue().at(0)) {} // BAD [NOT DETECTED] (see *)
|
||||
for (auto x : returnValue().at(0)) {} // BAD
|
||||
|
||||
for (auto x : returnRef()) {} // GOOD
|
||||
for (auto x : returnRef()[0]) {} // GOOD
|
||||
@@ -700,7 +700,7 @@ void test() {
|
||||
|
||||
{
|
||||
auto&& v = returnValue()[0];
|
||||
for(auto it = v.begin(); it != v.end(); ++it) {} // BAD [NOT DETECTED] (see *)
|
||||
for(auto it = v.begin(); it != v.end(); ++it) {} // BAD
|
||||
}
|
||||
|
||||
{
|
||||
@@ -713,7 +713,7 @@ void test() {
|
||||
for(auto it = v.begin(); it != v.end(); ++it) {} // GOOD
|
||||
}
|
||||
|
||||
for (auto x : return_self_by_ref(returnValue())) {} // BAD [NOT DETECTED] (see *)
|
||||
for (auto x : return_self_by_ref(returnValue())) {} // BAD
|
||||
|
||||
for (auto x : return_self_by_value(returnValue())) {} // GOOD
|
||||
}
|
||||
@@ -724,7 +724,7 @@ void iterate(const std::vector<T>& v) {
|
||||
}
|
||||
|
||||
std::vector<int>& ref_to_first_in_returnValue_1() {
|
||||
return returnValue()[0]; // BAD [NOT DETECTED] (see *)
|
||||
return returnValue()[0]; // BAD
|
||||
}
|
||||
|
||||
std::vector<int>& ref_to_first_in_returnValue_2() {
|
||||
@@ -732,7 +732,7 @@ std::vector<int>& ref_to_first_in_returnValue_2() {
|
||||
}
|
||||
|
||||
std::vector<int>& ref_to_first_in_returnValue_3() {
|
||||
return returnValue()[0]; // BAD [NOT DETECTED] (see *)
|
||||
return returnValue()[0]; // BAD
|
||||
}
|
||||
|
||||
std::vector<int> first_in_returnValue_1() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,12 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| coroutines.cpp:87:20:87:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:91:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:95:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:99:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:103:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:108:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -6,6 +6,12 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| coroutines.cpp:87:20:87:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:91:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:95:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:99:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:103:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:108:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
115
cpp/ql/test/library-tests/ir/ir/coroutines.cpp
Normal file
115
cpp/ql/test/library-tests/ir/ir/coroutines.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
namespace std {
|
||||
|
||||
template<class R, class... Args>
|
||||
struct coroutine_traits{
|
||||
using promise_type = R::promise_type;
|
||||
};
|
||||
|
||||
using nullptr_t = decltype(nullptr);
|
||||
|
||||
template<typename Promise>
|
||||
struct coroutine_handle {
|
||||
constexpr coroutine_handle() noexcept;
|
||||
constexpr coroutine_handle( std::nullptr_t ) noexcept;
|
||||
coroutine_handle(const coroutine_handle&) noexcept;
|
||||
coroutine_handle(coroutine_handle&&) noexcept;
|
||||
|
||||
static coroutine_handle from_promise(Promise&);
|
||||
coroutine_handle& operator=(nullptr_t) noexcept;
|
||||
coroutine_handle& operator=(const coroutine_handle&) noexcept;
|
||||
coroutine_handle& operator=(coroutine_handle&&) noexcept;
|
||||
constexpr operator coroutine_handle() const noexcept;
|
||||
|
||||
bool done() const;
|
||||
constexpr explicit operator bool() const noexcept;
|
||||
|
||||
void operator()() const;
|
||||
void resume() const;
|
||||
|
||||
void destroy() const;
|
||||
|
||||
Promise& promise() const;
|
||||
|
||||
constexpr void* address() const noexcept;
|
||||
static constexpr coroutine_handle from_address(void *);
|
||||
};
|
||||
|
||||
template<typename Promise>
|
||||
constexpr bool operator==(coroutine_handle<Promise>, coroutine_handle<Promise>) noexcept;
|
||||
|
||||
struct suspend_always {
|
||||
constexpr bool await_ready() const noexcept;
|
||||
template<typename Promise> constexpr void await_suspend(coroutine_handle<Promise>) const noexcept;
|
||||
constexpr void await_resume() const noexcept;
|
||||
};
|
||||
}
|
||||
|
||||
class co_returnable_void {
|
||||
public:
|
||||
struct promise_type;
|
||||
co_returnable_void(std::coroutine_handle<promise_type>);
|
||||
|
||||
co_returnable_void(co_returnable_void&) = delete;
|
||||
co_returnable_void(co_returnable_void&&) = delete;
|
||||
};
|
||||
|
||||
struct co_returnable_void::promise_type {
|
||||
std::coroutine_handle<promise_type> get_return_object();
|
||||
std::suspend_always initial_suspend() noexcept;
|
||||
std::suspend_always final_suspend() noexcept;
|
||||
|
||||
void return_void();
|
||||
void unhandled_exception();
|
||||
|
||||
std::suspend_always yield_value(int);
|
||||
};
|
||||
|
||||
class co_returnable_value {
|
||||
public:
|
||||
struct promise_type;
|
||||
co_returnable_value(std::coroutine_handle<promise_type>);
|
||||
|
||||
co_returnable_value(co_returnable_value&) = delete;
|
||||
co_returnable_value(co_returnable_value&&) = delete;
|
||||
};
|
||||
|
||||
struct co_returnable_value::promise_type {
|
||||
std::coroutine_handle<promise_type> get_return_object();
|
||||
std::suspend_always initial_suspend() noexcept;
|
||||
std::suspend_always final_suspend() noexcept;
|
||||
|
||||
void return_value(int);
|
||||
void unhandled_exception();
|
||||
|
||||
std::suspend_always yield_value(int);
|
||||
};
|
||||
|
||||
co_returnable_void co_return_void() {
|
||||
co_return;
|
||||
}
|
||||
|
||||
co_returnable_value co_return_int(int i) {
|
||||
co_return i;
|
||||
}
|
||||
|
||||
co_returnable_void co_yield_value_void(int i) {
|
||||
co_yield i;
|
||||
}
|
||||
|
||||
co_returnable_value co_yield_value_value(int i) {
|
||||
co_yield i;
|
||||
}
|
||||
|
||||
co_returnable_void co_yield_and_return_void(int i) {
|
||||
co_yield i;
|
||||
co_return;
|
||||
}
|
||||
|
||||
co_returnable_value co_yield_and_return_value(int i) {
|
||||
co_yield i;
|
||||
co_return (i + 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// semmle-extractor-options: --edg --c++20
|
||||
@@ -54,3 +54,51 @@ void temp_test7(bool b) {
|
||||
void temp_test8(bool b) {
|
||||
b ? throw ClassWithConstructor('x', ClassWithDestructor2().get_x()) : ClassWithDestructor2();
|
||||
}
|
||||
|
||||
void temp_test8_simple(bool b) {
|
||||
b ? throw ClassWithDestructor2().get_x() : 'a';
|
||||
}
|
||||
|
||||
struct string
|
||||
{
|
||||
string(const char *);
|
||||
~string();
|
||||
};
|
||||
|
||||
bool const_ref_string(const string &);
|
||||
|
||||
bool conditional_temp_via_conjunction(bool b)
|
||||
{
|
||||
return b && const_ref_string("");
|
||||
}
|
||||
|
||||
ClassWithDestructor2 make();
|
||||
|
||||
void temp_test9() {
|
||||
make();
|
||||
}
|
||||
|
||||
void temp_test10(int i) {
|
||||
while(i < 10) {
|
||||
make();
|
||||
}
|
||||
}
|
||||
|
||||
struct ClassWithDestructor3 {
|
||||
~ClassWithDestructor3();
|
||||
ClassWithDestructor2 getClassWithDestructor2();
|
||||
};
|
||||
|
||||
ClassWithDestructor3 makeClassWithDestructor3();
|
||||
|
||||
void temp_test11() {
|
||||
// Two destructors are called at the semicolon (i.e., they're both attached
|
||||
// to the call to `getClassWithDestructor2()`):
|
||||
// First, ~ClassWithDestructor2::ClassWithDestructor2(), and then the call
|
||||
// to `~ClassWithDestructor3::ClassWithDestructor3()`.
|
||||
makeClassWithDestructor3().getClassWithDestructor2();
|
||||
}
|
||||
|
||||
void temp_test12(ClassWithDestructor3 x) {
|
||||
x.getClassWithDestructor2().get_x() + 5;
|
||||
}
|
||||
@@ -2447,4 +2447,38 @@ void param_with_destructor_by_rref(ClassWithDestructor&& c) {
|
||||
// No destructor call should be here
|
||||
}
|
||||
|
||||
void rethrow_with_destruction(int x) {
|
||||
ClassWithDestructor c;
|
||||
throw;
|
||||
}
|
||||
|
||||
struct ByValueConstructor {
|
||||
ByValueConstructor(ClassWithDestructor);
|
||||
};
|
||||
|
||||
void new_with_destructor(ClassWithDestructor a)
|
||||
{
|
||||
ByValueConstructor* b = new ByValueConstructor(a);
|
||||
}
|
||||
|
||||
namespace rvalue_conversion_with_destructor {
|
||||
struct A {
|
||||
unsigned a;
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
~B();
|
||||
|
||||
inline A *operator->() const;
|
||||
};
|
||||
|
||||
B get();
|
||||
|
||||
void test()
|
||||
{
|
||||
auto a = get()->a;
|
||||
}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
@@ -1,4 +1,36 @@
|
||||
missingOperand
|
||||
| coroutines.cpp:87:20:88:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:88:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:88:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:88:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:92:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:92:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:92:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:92:11 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:96:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:96:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:96:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:96:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:96:13:96:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:96:13:96:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:100:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:100:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:100:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:100:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:100:13:100:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:100:13:100:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:104:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:104:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:104:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:104:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:104:13:104:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:104:13:104:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:109:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:109:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:109:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:109:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:109:13:109:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:109:13:109:13 | CopyValue: * ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
@@ -6,6 +38,93 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| coroutines.cpp:87:20:87:20 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:88:11 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:88:11 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:91:21 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:91:21 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:91:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:92:11 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:92:11 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:95:20 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:95:20 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:95:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:96:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:96:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:96:12:96:12 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:96:13:96:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:99:21 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:99:21 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:99:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:100:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:100:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:100:12:100:12 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:100:13:100:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:103:20 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:103:20 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:103:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:104:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:104:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:104:12:104:12 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:104:13:104:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:108:21 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:108:21 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:108:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:109:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:109:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:109:12:109:12 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:109:13:109:13 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | CopyValue: ... , ... | Instruction 'CopyValue: ... , ...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | CopyValue: ... , ... | Instruction 'CopyValue: ... , ...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | CopyValue: ... , ... | Instruction 'CopyValue: ... , ...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | CopyValue: ... , ... | Instruction 'CopyValue: ... , ...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | CopyValue: ... , ... | Instruction 'CopyValue: ... , ...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | CopyValue: ... , ... | Instruction 'CopyValue: ... , ...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | IndirectMayWriteSideEffect: (unnamed local variable) | Instruction 'IndirectMayWriteSideEffect: (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | IndirectReadSideEffect: (const suspend_always)... | Instruction 'IndirectReadSideEffect: (const suspend_always)...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | NoOp: label ...: | Instruction 'NoOp: label ...:' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | NoOp: label ...: | Instruction 'NoOp: label ...:' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | NoOp: label ...: | Instruction 'NoOp: label ...:' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | NoOp: label ...: | Instruction 'NoOp: label ...:' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | NoOp: label ...: | Instruction 'NoOp: label ...:' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | NoOp: label ...: | Instruction 'NoOp: label ...:' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
@@ -37,4 +156,32 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:91:21 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:91:21:91:21 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:95:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:95:20:95:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:96:3:96:3 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:99:21 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:99:21:99:21 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:100:3:100:3 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:103:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:103:20:103:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:104:3:104:3 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:108:21 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:108:21:108:21 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| coroutines.cpp:109:3:109:3 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
| file://:0:0:0:0 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
missingCppType
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,12 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| coroutines.cpp:87:20:87:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:91:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:95:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:99:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:103:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:108:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -6,6 +6,12 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| coroutines.cpp:87:20:87:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:91:21:91:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:91:21:91:33 | co_returnable_value co_return_int(int) | co_returnable_value co_return_int(int) |
|
||||
| coroutines.cpp:95:20:95:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:95:20:95:38 | co_returnable_void co_yield_value_void(int) | co_returnable_void co_yield_value_void(int) |
|
||||
| coroutines.cpp:99:21:99:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:99:21:99:40 | co_returnable_value co_yield_value_value(int) | co_returnable_value co_yield_value_value(int) |
|
||||
| coroutines.cpp:103:20:103:20 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:103:20:103:43 | co_returnable_void co_yield_and_return_void(int) | co_returnable_void co_yield_and_return_void(int) |
|
||||
| coroutines.cpp:108:21:108:21 | Uninitialized: declaration of (unnamed local variable) | Instruction 'Uninitialized: declaration of (unnamed local variable)' has no successors in function '$@'. | coroutines.cpp:108:21:108:45 | co_returnable_value co_yield_and_return_value(int) | co_returnable_value co_yield_and_return_value(int) |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -7,7 +7,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:38:5:38:5 | Chi: c106 | Instruction 'Chi: c106' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
ambiguousSuccessors
|
||||
|
||||
@@ -8,7 +8,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:38:5:38:5 | IndirectMayWriteSideEffect: c106 | Instruction 'IndirectMayWriteSideEffect: c106' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | Instruction 'CopyValue: (statement expression)' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
|
||||
@@ -7,7 +7,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:38:5:38:5 | IndirectMayWriteSideEffect: c106 | Instruction 'IndirectMayWriteSideEffect: c106' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
ambiguousSuccessors
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
edges
|
||||
| NonConstantFormat.c:28:27:28:30 | **argv | NonConstantFormat.c:30:10:30:16 | *access to array | provenance | |
|
||||
| NonConstantFormat.c:45:11:45:47 | *call to any_random_function | NonConstantFormat.c:45:9:45:48 | *call to gettext | provenance | |
|
||||
| NonConstantFormat.c:45:11:45:47 | *call to any_random_function | NonConstantFormat.c:45:9:45:48 | *call to gettext | provenance | DataFlowFunction |
|
||||
| nested.cpp:19:29:19:32 | *fmt0 | nested.cpp:21:23:21:26 | *fmt0 | provenance | |
|
||||
| nested.cpp:27:32:27:34 | *fmt | nested.cpp:28:16:28:18 | *fmt | provenance | |
|
||||
| nested.cpp:28:16:28:18 | *fmt | nested.cpp:19:29:19:32 | *fmt0 | provenance | |
|
||||
@@ -9,9 +9,9 @@ edges
|
||||
| nested.cpp:42:24:42:34 | *call to ext_fmt_str | nested.cpp:34:37:34:39 | *fmt | provenance | |
|
||||
| nested.cpp:86:19:86:46 | *call to __builtin_alloca | nested.cpp:87:18:87:20 | *fmt | provenance | |
|
||||
| test.cpp:46:27:46:30 | **argv | test.cpp:130:20:130:26 | *access to array | provenance | |
|
||||
| test.cpp:167:31:167:34 | *data | test.cpp:170:12:170:14 | *res | provenance | |
|
||||
| test.cpp:167:31:167:34 | *data | test.cpp:170:12:170:14 | *res | provenance | DataFlowFunction |
|
||||
| test.cpp:193:32:193:34 | *str | test.cpp:195:31:195:33 | *str | provenance | |
|
||||
| test.cpp:193:32:193:34 | *str | test.cpp:197:11:197:14 | *wstr | provenance | |
|
||||
| test.cpp:193:32:193:34 | *str | test.cpp:197:11:197:14 | *wstr | provenance | TaintFunction |
|
||||
| test.cpp:204:25:204:36 | *call to get_string | test.cpp:205:12:205:20 | *... + ... | provenance | |
|
||||
| test.cpp:204:25:204:36 | *call to get_string | test.cpp:206:12:206:16 | *hello | provenance | |
|
||||
| test.cpp:209:25:209:36 | *call to get_string | test.cpp:211:12:211:16 | *hello | provenance | |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
edges
|
||||
| test.c:8:27:8:30 | **argv | test.c:17:11:17:18 | *fileName | provenance | |
|
||||
| test.c:8:27:8:30 | **argv | test.c:17:11:17:18 | *fileName | provenance | TaintFunction |
|
||||
| test.c:8:27:8:30 | **argv | test.c:32:11:32:18 | *fileName | provenance | |
|
||||
| test.c:8:27:8:30 | **argv | test.c:57:10:57:16 | *access to array | provenance | |
|
||||
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | *fileName | provenance | |
|
||||
|
||||
@@ -14,17 +14,17 @@ edges
|
||||
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | *filename | provenance | |
|
||||
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | *path | provenance | |
|
||||
| test.cpp:93:17:93:24 | *filename | test.cpp:93:11:93:14 | strncat output argument | provenance | |
|
||||
| test.cpp:106:20:106:38 | *call to getenv | test.cpp:107:33:107:36 | *path | provenance | |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | *call to c_str | provenance | |
|
||||
| test.cpp:106:20:106:38 | *call to getenv | test.cpp:107:33:107:36 | *path | provenance | TaintFunction |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | *call to c_str | provenance | TaintFunction |
|
||||
| test.cpp:107:33:107:36 | *path | test.cpp:107:31:107:31 | call to operator+ | provenance | |
|
||||
| test.cpp:113:20:113:38 | *call to getenv | test.cpp:114:19:114:22 | *path | provenance | |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | *call to c_str | provenance | |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | *call to c_str | provenance | |
|
||||
| test.cpp:113:20:113:38 | *call to getenv | test.cpp:114:19:114:22 | *path | provenance | TaintFunction |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | *call to c_str | provenance | TaintFunction |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | *call to c_str | provenance | TaintFunction |
|
||||
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:10:114:23 | call to operator+ | provenance | |
|
||||
| test.cpp:114:19:114:22 | *path | test.cpp:114:10:114:23 | call to operator+ | provenance | |
|
||||
| test.cpp:114:19:114:22 | *path | test.cpp:114:17:114:17 | call to operator+ | provenance | |
|
||||
| test.cpp:119:20:119:38 | *call to getenv | test.cpp:120:19:120:22 | *path | provenance | |
|
||||
| test.cpp:120:17:120:17 | call to operator+ | test.cpp:120:10:120:30 | *call to data | provenance | |
|
||||
| test.cpp:119:20:119:38 | *call to getenv | test.cpp:120:19:120:22 | *path | provenance | TaintFunction |
|
||||
| test.cpp:120:17:120:17 | call to operator+ | test.cpp:120:10:120:30 | *call to data | provenance | TaintFunction |
|
||||
| test.cpp:120:19:120:22 | *path | test.cpp:120:17:120:17 | call to operator+ | provenance | |
|
||||
| test.cpp:140:9:140:11 | fread output argument | test.cpp:142:31:142:33 | *str | provenance | |
|
||||
| test.cpp:142:11:142:17 | sprintf output argument | test.cpp:143:10:143:16 | *command | provenance | |
|
||||
@@ -34,31 +34,31 @@ edges
|
||||
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:178:22:178:26 | *flags | provenance | |
|
||||
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:178:22:178:26 | *flags | provenance | |
|
||||
| test.cpp:177:20:177:27 | *filename | test.cpp:177:13:177:17 | strncat output argument | provenance | |
|
||||
| test.cpp:177:20:177:27 | *filename | test.cpp:177:13:177:17 | strncat output argument | provenance | |
|
||||
| test.cpp:177:20:177:27 | *filename | test.cpp:177:13:177:17 | strncat output argument | provenance | TaintFunction |
|
||||
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | *command | provenance | |
|
||||
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | *command | provenance | |
|
||||
| test.cpp:178:22:178:26 | *flags | test.cpp:178:13:178:19 | strncat output argument | provenance | |
|
||||
| test.cpp:178:22:178:26 | *flags | test.cpp:178:13:178:19 | strncat output argument | provenance | |
|
||||
| test.cpp:178:22:178:26 | *flags | test.cpp:178:13:178:19 | strncat output argument | provenance | TaintFunction |
|
||||
| test.cpp:180:13:180:19 | strncat output argument | test.cpp:183:32:183:38 | *command | provenance | |
|
||||
| test.cpp:180:22:180:29 | *filename | test.cpp:180:13:180:19 | strncat output argument | provenance | |
|
||||
| test.cpp:186:47:186:54 | *filename | test.cpp:187:18:187:25 | *filename | provenance | |
|
||||
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:20:188:24 | *flags | provenance | |
|
||||
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:20:188:24 | *flags | provenance | |
|
||||
| test.cpp:187:18:187:25 | *filename | test.cpp:187:11:187:15 | strncat output argument | provenance | |
|
||||
| test.cpp:187:18:187:25 | *filename | test.cpp:187:11:187:15 | strncat output argument | provenance | |
|
||||
| test.cpp:187:18:187:25 | *filename | test.cpp:187:11:187:15 | strncat output argument | provenance | TaintFunction |
|
||||
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:186:19:186:25 | *command | provenance | |
|
||||
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:186:19:186:25 | *command | provenance | |
|
||||
| test.cpp:188:20:188:24 | *flags | test.cpp:188:11:188:17 | strncat output argument | provenance | |
|
||||
| test.cpp:188:20:188:24 | *flags | test.cpp:188:11:188:17 | strncat output argument | provenance | |
|
||||
| test.cpp:188:20:188:24 | *flags | test.cpp:188:11:188:17 | strncat output argument | provenance | TaintFunction |
|
||||
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | *filename | provenance | |
|
||||
| test.cpp:196:10:196:16 | concat output argument | test.cpp:198:32:198:38 | *command | provenance | |
|
||||
| test.cpp:196:10:196:16 | concat output argument | test.cpp:198:32:198:38 | *command | provenance | |
|
||||
| test.cpp:196:26:196:33 | *filename | test.cpp:186:47:186:54 | *filename | provenance | |
|
||||
| test.cpp:196:26:196:33 | *filename | test.cpp:196:10:196:16 | concat output argument | provenance | |
|
||||
| test.cpp:196:26:196:33 | *filename | test.cpp:196:10:196:16 | concat output argument | provenance | |
|
||||
| test.cpp:196:26:196:33 | *filename | test.cpp:196:10:196:16 | concat output argument | provenance | TaintFunction |
|
||||
| test.cpp:196:26:196:33 | *filename | test.cpp:196:10:196:16 | concat output argument | provenance | TaintFunction |
|
||||
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | *filename | provenance | |
|
||||
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument | provenance | |
|
||||
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument | provenance | |
|
||||
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument | provenance | TaintFunction |
|
||||
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument | provenance | TaintFunction |
|
||||
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | *command | provenance | |
|
||||
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | *command | provenance | |
|
||||
| test.cpp:220:19:220:26 | *filename | test.cpp:220:10:220:16 | strncat output argument | provenance | |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
edges
|
||||
| search.c:14:24:14:28 | *query | search.c:17:8:17:12 | *query | provenance | |
|
||||
| search.c:22:24:22:28 | *query | search.c:23:39:23:43 | *query | provenance | |
|
||||
| search.c:55:24:55:28 | *query | search.c:62:8:62:17 | *query_text | provenance | |
|
||||
| search.c:55:24:55:28 | *query | search.c:62:8:62:17 | *query_text | provenance | TaintFunction |
|
||||
| search.c:67:21:67:26 | *call to getenv | search.c:71:17:71:25 | *raw_query | provenance | |
|
||||
| search.c:67:21:67:26 | *call to getenv | search.c:73:17:73:25 | *raw_query | provenance | |
|
||||
| search.c:67:21:67:26 | *call to getenv | search.c:77:17:77:25 | *raw_query | provenance | |
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
edges
|
||||
| test.c:14:27:14:30 | **argv | test.c:21:18:21:23 | *query1 | provenance | |
|
||||
| test.c:14:27:14:30 | **argv | test.c:21:18:21:23 | *query1 | provenance | TaintFunction |
|
||||
| test.c:14:27:14:30 | **argv | test.c:35:16:35:23 | *userName | provenance | |
|
||||
| test.c:35:16:35:23 | *userName | test.c:40:25:40:32 | *username | provenance | |
|
||||
| test.c:38:7:38:20 | **globalUsername | test.c:51:18:51:23 | *query1 | provenance | |
|
||||
| test.c:38:7:38:20 | **globalUsername | test.c:51:18:51:23 | *query1 | provenance | TaintFunction |
|
||||
| test.c:40:25:40:32 | *username | test.c:38:7:38:20 | **globalUsername | provenance | |
|
||||
| test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | *userInput | provenance | |
|
||||
| test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | *userInput | provenance | |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
edges
|
||||
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | *data | provenance | |
|
||||
| test.cpp:64:30:64:35 | *call to getenv | test.cpp:73:24:73:27 | *data | provenance | |
|
||||
| test.cpp:64:30:64:35 | *call to getenv | test.cpp:73:24:73:27 | *data | provenance | TaintFunction |
|
||||
| test.cpp:73:24:73:27 | *data | test.cpp:37:73:37:76 | *data | provenance | |
|
||||
nodes
|
||||
| test.cpp:37:73:37:76 | *data | semmle.label | *data |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
edges
|
||||
| CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:30:19:30:29 | fgets output argument | CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:52:20:52:23 | data | provenance | |
|
||||
| CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:30:19:30:29 | fgets output argument | CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:52:20:52:23 | data | provenance | TaintFunction |
|
||||
nodes
|
||||
| CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:30:19:30:29 | fgets output argument | semmle.label | fgets output argument |
|
||||
| CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:52:20:52:23 | data | semmle.label | data |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
edges
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:9:9:9:9 | i | provenance | |
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:11:9:11:9 | i | provenance | |
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:13:9:13:9 | i | provenance | |
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:9:9:9:9 | i | provenance | TaintFunction |
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:11:9:11:9 | i | provenance | TaintFunction |
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:13:9:13:9 | i | provenance | TaintFunction |
|
||||
| test1.c:9:9:9:9 | i | test1.c:16:16:16:16 | i | provenance | |
|
||||
| test1.c:11:9:11:9 | i | test1.c:32:16:32:16 | i | provenance | |
|
||||
| test1.c:13:9:13:9 | i | test1.c:48:16:48:16 | i | provenance | |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
edges
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | *data | provenance | |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | *data | provenance | |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | *call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | *data | provenance | |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | *call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | *data | provenance | TaintFunction |
|
||||
nodes
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | semmle.label | recv output argument |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | *data | semmle.label | *data |
|
||||
|
||||
@@ -11,20 +11,20 @@ edges
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:107:15:107:19 | *access to array | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:110:9:110:11 | ** ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:111:15:111:17 | ** ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:116:9:116:10 | *i3 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:117:15:117:16 | *i3 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:117:15:117:16 | *i3 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:121:9:121:10 | *i4 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:122:15:122:16 | *i4 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:122:15:122:16 | *i4 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:116:9:116:10 | *i3 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:117:15:117:16 | *i3 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:117:15:117:16 | *i3 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:121:9:121:10 | *i4 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:122:15:122:16 | *i4 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:122:15:122:16 | *i4 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:127:9:127:10 | *i5 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:128:15:128:16 | *i5 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:128:15:128:16 | *i5 | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:131:9:131:14 | *... + ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:132:15:132:20 | *... + ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:132:15:132:20 | *... + ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:135:9:135:12 | *... ++ | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:136:15:136:18 | *-- ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:135:9:135:12 | *... ++ | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:136:15:136:18 | *-- ... | provenance | DataFlowFunction |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:139:9:139:26 | *... ? ... : ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:140:15:140:32 | *... ? ... : ... | provenance | |
|
||||
| argvLocal.c:13:27:13:30 | **argv | argvLocal.c:144:9:144:10 | *i7 | provenance | |
|
||||
@@ -41,20 +41,20 @@ edges
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:107:15:107:19 | *access to array | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:110:9:110:11 | ** ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:111:15:111:17 | ** ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:116:9:116:10 | *i3 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:117:15:117:16 | *i3 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:117:15:117:16 | *i3 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:121:9:121:10 | *i4 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:122:15:122:16 | *i4 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:122:15:122:16 | *i4 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:116:9:116:10 | *i3 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:117:15:117:16 | *i3 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:117:15:117:16 | *i3 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:121:9:121:10 | *i4 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:122:15:122:16 | *i4 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:122:15:122:16 | *i4 | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:127:9:127:10 | *i5 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:128:15:128:16 | *i5 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:128:15:128:16 | *i5 | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:131:9:131:14 | *... + ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:132:15:132:20 | *... + ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:132:15:132:20 | *... + ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:135:9:135:12 | *... ++ | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:136:15:136:18 | *-- ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:135:9:135:12 | *... ++ | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:136:15:136:18 | *-- ... | provenance | DataFlowFunction |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:139:9:139:26 | *... ? ... : ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:140:15:140:32 | *... ? ... : ... | provenance | |
|
||||
| argvLocal.c:96:15:96:21 | printWrapper output argument | argvLocal.c:144:9:144:10 | *i7 | provenance | |
|
||||
|
||||
@@ -9,7 +9,7 @@ edges
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:116:9:116:13 | *access to array | provenance | |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:121:9:121:10 | *v8 | provenance | |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:130:9:130:10 | *v9 | provenance | |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:135:9:135:11 | *v10 | provenance | |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:135:9:135:11 | *v10 | provenance | TaintFunction |
|
||||
| consts.cpp:90:7:90:10 | *call to gets | consts.cpp:91:9:91:10 | *v2 | provenance | |
|
||||
| consts.cpp:90:7:90:10 | *call to gets | consts.cpp:116:9:116:13 | *access to array | provenance | |
|
||||
| consts.cpp:90:7:90:10 | *call to gets | consts.cpp:121:9:121:10 | *v8 | provenance | |
|
||||
@@ -19,7 +19,7 @@ edges
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:116:9:116:13 | *access to array | provenance | |
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:121:9:121:10 | *v8 | provenance | |
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:130:9:130:10 | *v9 | provenance | |
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:135:9:135:11 | *v10 | provenance | |
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:135:9:135:11 | *v10 | provenance | TaintFunction |
|
||||
| consts.cpp:106:13:106:19 | *call to varFunc | consts.cpp:107:9:107:10 | *v5 | provenance | |
|
||||
| consts.cpp:111:7:111:13 | *call to varFunc | consts.cpp:112:9:112:10 | *v6 | provenance | |
|
||||
| consts.cpp:139:13:139:16 | readString output argument | consts.cpp:140:9:140:11 | *v11 | provenance | |
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
edges
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:43:38:43:44 | tainted | provenance | |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:44:38:44:63 | ... * ... | provenance | |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:46:38:46:63 | ... + ... | provenance | |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:49:32:49:35 | size | provenance | |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:50:17:50:30 | size | provenance | |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:53:35:53:60 | ... * ... | provenance | |
|
||||
| test.cpp:124:18:124:31 | *call to getenv | test.cpp:128:24:128:41 | ... * ... | provenance | |
|
||||
| test.cpp:133:19:133:32 | *call to getenv | test.cpp:135:10:135:27 | ... * ... | provenance | |
|
||||
| test.cpp:148:20:148:33 | *call to getenv | test.cpp:152:11:152:28 | ... * ... | provenance | |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:43:38:43:44 | tainted | provenance | TaintFunction |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:44:38:44:63 | ... * ... | provenance | TaintFunction |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:46:38:46:63 | ... + ... | provenance | TaintFunction |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:49:32:49:35 | size | provenance | TaintFunction |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:50:17:50:30 | size | provenance | TaintFunction |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:53:35:53:60 | ... * ... | provenance | TaintFunction |
|
||||
| test.cpp:124:18:124:31 | *call to getenv | test.cpp:128:24:128:41 | ... * ... | provenance | TaintFunction |
|
||||
| test.cpp:133:19:133:32 | *call to getenv | test.cpp:135:10:135:27 | ... * ... | provenance | TaintFunction |
|
||||
| test.cpp:148:20:148:33 | *call to getenv | test.cpp:152:11:152:28 | ... * ... | provenance | TaintFunction |
|
||||
| test.cpp:209:8:209:23 | *get_tainted_size | test.cpp:241:9:241:24 | call to get_tainted_size | provenance | |
|
||||
| test.cpp:211:14:211:27 | *call to getenv | test.cpp:209:8:209:23 | *get_tainted_size | provenance | |
|
||||
| test.cpp:211:14:211:27 | *call to getenv | test.cpp:209:8:209:23 | *get_tainted_size | provenance | TaintFunction |
|
||||
| test.cpp:230:21:230:21 | s | test.cpp:231:21:231:21 | s | provenance | |
|
||||
| test.cpp:237:24:237:37 | *call to getenv | test.cpp:239:9:239:18 | local_size | provenance | |
|
||||
| test.cpp:237:24:237:37 | *call to getenv | test.cpp:245:11:245:20 | local_size | provenance | |
|
||||
| test.cpp:237:24:237:37 | *call to getenv | test.cpp:247:10:247:19 | local_size | provenance | |
|
||||
| test.cpp:237:24:237:37 | *call to getenv | test.cpp:239:9:239:18 | local_size | provenance | TaintFunction |
|
||||
| test.cpp:237:24:237:37 | *call to getenv | test.cpp:245:11:245:20 | local_size | provenance | TaintFunction |
|
||||
| test.cpp:237:24:237:37 | *call to getenv | test.cpp:247:10:247:19 | local_size | provenance | TaintFunction |
|
||||
| test.cpp:247:10:247:19 | local_size | test.cpp:230:21:230:21 | s | provenance | |
|
||||
| test.cpp:250:20:250:27 | *out_size | test.cpp:289:17:289:20 | get_size output argument | provenance | |
|
||||
| test.cpp:250:20:250:27 | *out_size | test.cpp:305:18:305:21 | get_size output argument | provenance | |
|
||||
| test.cpp:251:18:251:31 | *call to getenv | test.cpp:250:20:250:27 | *out_size | provenance | |
|
||||
| test.cpp:259:20:259:33 | *call to getenv | test.cpp:263:11:263:29 | ... * ... | provenance | |
|
||||
| test.cpp:251:18:251:31 | *call to getenv | test.cpp:250:20:250:27 | *out_size | provenance | TaintFunction |
|
||||
| test.cpp:259:20:259:33 | *call to getenv | test.cpp:263:11:263:29 | ... * ... | provenance | TaintFunction |
|
||||
| test.cpp:289:17:289:20 | get_size output argument | test.cpp:291:11:291:28 | ... * ... | provenance | |
|
||||
| test.cpp:305:18:305:21 | get_size output argument | test.cpp:308:10:308:27 | ... * ... | provenance | |
|
||||
| test.cpp:353:18:353:31 | *call to getenv | test.cpp:355:35:355:38 | size | provenance | |
|
||||
| test.cpp:353:18:353:31 | *call to getenv | test.cpp:356:35:356:38 | size | provenance | |
|
||||
| test.cpp:353:18:353:31 | *call to getenv | test.cpp:355:35:355:38 | size | provenance | TaintFunction |
|
||||
| test.cpp:353:18:353:31 | *call to getenv | test.cpp:356:35:356:38 | size | provenance | TaintFunction |
|
||||
nodes
|
||||
| test.cpp:39:27:39:30 | **argv | semmle.label | **argv |
|
||||
| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
|
||||
|
||||
@@ -2,18 +2,18 @@ edges
|
||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v | provenance | |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v | provenance | |
|
||||
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v | provenance | |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num | provenance | |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | provenance | |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | provenance | |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | provenance | |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | provenance | |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num | provenance | TaintFunction |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | provenance | TaintFunction |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:17:6:17:18 | call to getTaintedInt | provenance | |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:18:6:18:18 | call to getTaintedInt | provenance | |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | *getTaintedInt | provenance | |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | *getTaintedInt | provenance | TaintFunction |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y | provenance | |
|
||||
| test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | provenance | |
|
||||
| test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | provenance | |
|
||||
| test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | provenance | |
|
||||
| test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | provenance | TaintFunction |
|
||||
| test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | provenance | TaintFunction |
|
||||
| test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | provenance | TaintFunction |
|
||||
nodes
|
||||
| test2.cpp:12:21:12:21 | v | semmle.label | v |
|
||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
edges
|
||||
| test2.cpp:62:18:62:25 | password | test2.cpp:65:31:65:34 | cpy1 | provenance | |
|
||||
| test2.cpp:72:15:72:24 | password | test2.cpp:73:30:73:32 | *buf | provenance | |
|
||||
| test2.cpp:98:45:98:52 | password | test2.cpp:99:27:99:32 | *buffer | provenance | |
|
||||
| test2.cpp:72:15:72:24 | password | test2.cpp:73:30:73:32 | *buf | provenance | DataFlowFunction |
|
||||
| test2.cpp:98:45:98:52 | password | test2.cpp:99:27:99:32 | *buffer | provenance | TaintFunction |
|
||||
| test.cpp:70:38:70:48 | thePassword | test.cpp:73:43:73:53 | thePassword | provenance | |
|
||||
| test.cpp:73:63:73:73 | thePassword | test.cpp:73:43:73:53 | thePassword | provenance | |
|
||||
nodes
|
||||
|
||||
@@ -10,8 +10,8 @@ edges
|
||||
| test3.cpp:138:24:138:32 | password1 | test3.cpp:117:28:117:33 | buffer | provenance | |
|
||||
| test3.cpp:138:24:138:32 | password1 | test3.cpp:138:21:138:22 | call to id | provenance | |
|
||||
| test3.cpp:144:16:144:29 | call to get_global_str | test3.cpp:146:15:146:18 | data | provenance | |
|
||||
| test3.cpp:157:19:157:26 | password | test3.cpp:159:15:159:20 | *buffer | provenance | |
|
||||
| test3.cpp:270:16:270:23 | password | test3.cpp:272:15:272:18 | *data | provenance | |
|
||||
| test3.cpp:157:19:157:26 | password | test3.cpp:159:15:159:20 | *buffer | provenance | TaintFunction |
|
||||
| test3.cpp:270:16:270:23 | password | test3.cpp:272:15:272:18 | *data | provenance | DataFlowFunction |
|
||||
| test3.cpp:278:20:278:23 | data | test3.cpp:280:14:280:17 | data | provenance | |
|
||||
| test3.cpp:283:20:283:23 | data | test3.cpp:285:14:285:17 | data | provenance | |
|
||||
| test3.cpp:288:20:288:23 | data | test3.cpp:290:14:290:17 | data | provenance | |
|
||||
@@ -25,10 +25,10 @@ edges
|
||||
| test3.cpp:322:16:322:24 | password2 | test3.cpp:325:11:325:14 | data | provenance | |
|
||||
| test3.cpp:324:11:324:14 | data | test3.cpp:293:20:293:23 | data | provenance | |
|
||||
| test3.cpp:325:11:325:14 | data | test3.cpp:298:20:298:23 | data | provenance | |
|
||||
| test3.cpp:526:44:526:54 | my_latitude | test3.cpp:527:15:527:20 | *buffer | provenance | |
|
||||
| test3.cpp:532:45:532:58 | home_longitude | test3.cpp:533:15:533:20 | *buffer | provenance | |
|
||||
| test3.cpp:551:47:551:58 | salaryString | test3.cpp:552:15:552:20 | *buffer | provenance | |
|
||||
| test3.cpp:556:19:556:30 | salaryString | test3.cpp:559:15:559:20 | *buffer | provenance | |
|
||||
| test3.cpp:526:44:526:54 | my_latitude | test3.cpp:527:15:527:20 | *buffer | provenance | TaintFunction |
|
||||
| test3.cpp:532:45:532:58 | home_longitude | test3.cpp:533:15:533:20 | *buffer | provenance | TaintFunction |
|
||||
| test3.cpp:551:47:551:58 | salaryString | test3.cpp:552:15:552:20 | *buffer | provenance | TaintFunction |
|
||||
| test3.cpp:556:19:556:30 | salaryString | test3.cpp:559:15:559:20 | *buffer | provenance | TaintFunction |
|
||||
| test3.cpp:571:8:571:21 | call to get_home_phone | test3.cpp:572:14:572:16 | str | provenance | |
|
||||
| test3.cpp:577:8:577:23 | call to get_home_address | test3.cpp:578:14:578:16 | str | provenance | |
|
||||
nodes
|
||||
|
||||
@@ -8,9 +8,9 @@ edges
|
||||
| test.cpp:38:11:38:15 | *url_g | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:39:11:39:15 | *url_l | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:40:11:40:17 | *access to array | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:46:18:46:26 | *http:// | test.cpp:49:11:49:16 | *buffer | provenance | |
|
||||
| test.cpp:46:18:46:26 | *http:// | test.cpp:49:11:49:16 | *buffer | provenance | DataFlowFunction |
|
||||
| test.cpp:49:11:49:16 | *buffer | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:110:21:110:40 | *http://example.com | test.cpp:121:11:121:13 | *ptr | provenance | |
|
||||
| test.cpp:110:21:110:40 | *http://example.com | test.cpp:121:11:121:13 | *ptr | provenance | TaintFunction |
|
||||
| test.cpp:121:11:121:13 | *ptr | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
nodes
|
||||
| test.cpp:11:26:11:28 | *url | semmle.label | *url |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
edges
|
||||
| tests2.cpp:50:13:50:19 | **global1 | tests2.cpp:82:14:82:20 | *global1 | provenance | |
|
||||
| tests2.cpp:50:23:50:43 | *call to mysql_get_client_info | tests2.cpp:50:13:50:19 | **global1 | provenance | |
|
||||
| tests2.cpp:78:18:78:38 | *call to mysql_get_client_info | tests2.cpp:81:14:81:19 | *buffer | provenance | |
|
||||
| tests2.cpp:78:18:78:38 | *call to mysql_get_client_info | tests2.cpp:81:14:81:19 | *buffer | provenance | DataFlowFunction |
|
||||
| tests2.cpp:91:42:91:45 | *str1 | tests2.cpp:93:14:93:17 | *str1 | provenance | |
|
||||
| tests2.cpp:101:8:101:15 | *call to getpwuid | tests2.cpp:102:14:102:15 | *pw | provenance | |
|
||||
| tests2.cpp:109:3:109:4 | *c1 [post update] [*ptr] | tests2.cpp:111:14:111:15 | *c1 [*ptr] | provenance | |
|
||||
|
||||
@@ -5,7 +5,7 @@ edges
|
||||
| tests.cpp:86:29:86:31 | *msg | tests.cpp:88:15:88:17 | *msg | provenance | |
|
||||
| tests.cpp:97:13:97:34 | *call to getenv | tests.cpp:86:29:86:31 | *msg | provenance | |
|
||||
| tests.cpp:107:30:107:32 | *msg | tests.cpp:111:15:111:17 | *tmp | provenance | |
|
||||
| tests.cpp:114:30:114:32 | *msg | tests.cpp:119:7:119:12 | *buffer | provenance | |
|
||||
| tests.cpp:114:30:114:32 | *msg | tests.cpp:119:7:119:12 | *buffer | provenance | TaintFunction |
|
||||
| tests.cpp:122:30:122:32 | *msg | tests.cpp:124:15:124:17 | *msg | provenance | |
|
||||
| tests.cpp:131:14:131:35 | *call to getenv | tests.cpp:107:30:107:32 | *msg | provenance | |
|
||||
| tests.cpp:132:14:132:35 | *call to getenv | tests.cpp:114:30:114:32 | *msg | provenance | |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
edges
|
||||
| test.cpp:20:29:20:47 | *call to getenv | test.cpp:24:10:24:35 | ! ... | provenance | |
|
||||
| test.cpp:20:29:20:47 | *call to getenv | test.cpp:24:10:24:35 | ! ... | provenance | TaintFunction |
|
||||
nodes
|
||||
| test.cpp:20:29:20:47 | *call to getenv | semmle.label | *call to getenv |
|
||||
| test.cpp:24:10:24:35 | ! ... | semmle.label | ! ... |
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInfo($"AssemblyLookupLocation: Skipping {dll.FullName}.");
|
||||
logger.LogDebug($"AssemblyLookupLocation: Skipping {dll.FullName}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,19 +68,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInfo($"AssemblyLookupLocation: Skipping {path}.");
|
||||
logger.LogDebug($"AssemblyLookupLocation: Skipping {path}.");
|
||||
}
|
||||
return dllsToIndex;
|
||||
}
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
logger.LogInfo($"AssemblyLookupLocation: Finding reference DLLs in {path}...");
|
||||
logger.LogDebug($"AssemblyLookupLocation: Finding reference DLLs in {path}...");
|
||||
AddReferenceDirectory(dllsToIndex, logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInfo("AssemblyLookupLocation: Path not found: " + path);
|
||||
logger.LogDebug("AssemblyLookupLocation: Path not found: " + path);
|
||||
}
|
||||
return dllsToIndex;
|
||||
}
|
||||
|
||||
@@ -12,14 +12,26 @@ using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
public interface ICompilationInfoContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// List of `(key, value)` tuples, that are stored in the DB for telemetry purposes.
|
||||
/// </summary>
|
||||
List<(string, string)> CompilationInfos { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main implementation of the build analysis.
|
||||
/// </summary>
|
||||
public sealed partial class DependencyManager : IDisposable
|
||||
public sealed partial class DependencyManager : IDisposable, ICompilationInfoContainer
|
||||
{
|
||||
private readonly AssemblyCache assemblyCache;
|
||||
private readonly ILogger logger;
|
||||
private readonly IDiagnosticsWriter diagnosticsWriter;
|
||||
private readonly NugetPackageRestorer nugetPackageRestorer;
|
||||
private readonly IDotNet dotnet;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly FileProvider fileProvider;
|
||||
|
||||
// Only used as a set, but ConcurrentDictionary is the only concurrent set in .NET.
|
||||
private readonly IDictionary<string, bool> usedReferences = new ConcurrentDictionary<string, bool>();
|
||||
@@ -30,17 +42,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
private int conflictedReferences = 0;
|
||||
private readonly DirectoryInfo sourceDir;
|
||||
private string? dotnetPath;
|
||||
private readonly IDotNet dotnet;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly TemporaryDirectory packageDirectory;
|
||||
private readonly TemporaryDirectory legacyPackageDirectory;
|
||||
private readonly TemporaryDirectory missingPackageDirectory;
|
||||
|
||||
private readonly TemporaryDirectory tempWorkingDirectory;
|
||||
private readonly bool cleanupTempWorkingDirectory;
|
||||
|
||||
private readonly Lazy<Runtime> runtimeLazy;
|
||||
private Runtime Runtime => runtimeLazy.Value;
|
||||
private readonly int threads = EnvironmentVariables.GetDefaultNumberOfThreads();
|
||||
|
||||
internal static readonly int Threads = EnvironmentVariables.GetDefaultNumberOfThreads();
|
||||
|
||||
/// <summary>
|
||||
/// Performs C# dependency fetching.
|
||||
@@ -73,26 +82,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
$"dependency-manager-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc"));
|
||||
this.sourceDir = new DirectoryInfo(srcDir);
|
||||
|
||||
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "packages"));
|
||||
legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "legacypackages"));
|
||||
missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "missingpackages"));
|
||||
tempWorkingDirectory = new TemporaryDirectory(
|
||||
FileUtils.GetTemporaryWorkingDirectory(out cleanupTempWorkingDirectory),
|
||||
"temporary working",
|
||||
logger);
|
||||
|
||||
tempWorkingDirectory = new TemporaryDirectory(FileUtils.GetTemporaryWorkingDirectory(out cleanupTempWorkingDirectory));
|
||||
|
||||
logger.LogInfo($"Finding files in {srcDir}...");
|
||||
|
||||
var allFiles = GetAllFiles().ToList();
|
||||
var binaryFileExtensions = new HashSet<string>(new[] { ".dll", ".exe" }); // TODO: add more binary file extensions.
|
||||
var allNonBinaryFiles = allFiles.Where(f => !binaryFileExtensions.Contains(f.Extension.ToLowerInvariant())).ToList();
|
||||
var smallNonBinaryFiles = allNonBinaryFiles.SelectSmallFiles(logger).SelectFileNames().ToList();
|
||||
this.fileContent = new FileContent(logger, smallNonBinaryFiles);
|
||||
this.nonGeneratedSources = allNonBinaryFiles.SelectFileNamesByExtension(".cs").ToList();
|
||||
this.generatedSources = new();
|
||||
var allProjects = allNonBinaryFiles.SelectFileNamesByExtension(".csproj").ToList();
|
||||
var allSolutions = allNonBinaryFiles.SelectFileNamesByExtension(".sln").ToList();
|
||||
var dllLocations = allFiles.SelectFileNamesByExtension(".dll").Select(x => new AssemblyLookupLocation(x)).ToHashSet();
|
||||
|
||||
logger.LogInfo($"Found {allFiles.Count} files, {nonGeneratedSources.Count} source files, {allProjects.Count} project files, {allSolutions.Count} solution files, {dllLocations.Count} DLLs.");
|
||||
this.fileProvider = new FileProvider(sourceDir, logger);
|
||||
this.fileContent = new FileContent(logger, this.fileProvider.SmallNonBinary);
|
||||
this.nonGeneratedSources = fileProvider.Sources.ToList();
|
||||
this.generatedSources = [];
|
||||
|
||||
void startCallback(string s, bool silent)
|
||||
{
|
||||
@@ -104,7 +102,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
logger.Log(silent ? Severity.Debug : Severity.Info, $"Exit code {ret}{(string.IsNullOrEmpty(msg) ? "" : $": {msg}")}");
|
||||
}
|
||||
|
||||
DotNet.WithDotNet(SystemBuildActions.Instance, logger, smallNonBinaryFiles, tempWorkingDirectory.ToString(), shouldCleanUp: false, ensureDotNetAvailable: true, version: null, installDir =>
|
||||
DotNet.WithDotNet(SystemBuildActions.Instance, logger, fileProvider.GlobalJsons, tempWorkingDirectory.ToString(), shouldCleanUp: false, ensureDotNetAvailable: true, version: null, installDir =>
|
||||
{
|
||||
this.dotnetPath = installDir;
|
||||
return BuildScript.Success;
|
||||
@@ -121,13 +119,16 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
throw;
|
||||
}
|
||||
|
||||
RestoreNugetPackages(allNonBinaryFiles, allProjects, allSolutions, dllLocations);
|
||||
nugetPackageRestorer = new NugetPackageRestorer(fileProvider, fileContent, dotnet, diagnosticsWriter, logger, this);
|
||||
|
||||
var dllLocations = fileProvider.Dlls.Select(x => new AssemblyLookupLocation(x)).ToHashSet();
|
||||
dllLocations.UnionWith(nugetPackageRestorer.Restore());
|
||||
// Find DLLs in the .Net / Asp.Net Framework
|
||||
// This needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
|
||||
var frameworkLocations = AddFrameworkDlls(dllLocations);
|
||||
|
||||
assemblyCache = new AssemblyCache(dllLocations, frameworkLocations, logger);
|
||||
AnalyseSolutions(allSolutions);
|
||||
AnalyseSolutions(fileProvider.Solutions);
|
||||
|
||||
foreach (var filename in assemblyCache.AllAssemblies.Select(a => a.Filename))
|
||||
{
|
||||
@@ -140,39 +141,35 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
// Output the findings
|
||||
foreach (var r in usedReferences.Keys.OrderBy(r => r))
|
||||
{
|
||||
logger.LogInfo($"Resolved reference {r}");
|
||||
logger.LogDebug($"Resolved reference {r}");
|
||||
}
|
||||
|
||||
foreach (var r in unresolvedReferences.OrderBy(r => r.Key))
|
||||
{
|
||||
logger.LogInfo($"Unresolved reference {r.Key} in project {r.Value}");
|
||||
logger.LogDebug($"Unresolved reference {r.Key} in project {r.Value}");
|
||||
}
|
||||
|
||||
var webViewExtractionOption = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WebViewGeneration);
|
||||
if (webViewExtractionOption == null ||
|
||||
bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
|
||||
shouldExtractWebViews)
|
||||
var sourceGenerators = new ISourceGenerator[]
|
||||
{
|
||||
CompilationInfos.Add(("WebView extraction enabled", "1"));
|
||||
GenerateSourceFilesFromWebViews(allNonBinaryFiles);
|
||||
}
|
||||
else
|
||||
new ImplicitUsingsGenerator(fileContent, logger, tempWorkingDirectory),
|
||||
new WebViewGenerator(fileProvider, fileContent, dotnet, this, logger, tempWorkingDirectory, usedReferences.Keys)
|
||||
};
|
||||
|
||||
foreach (var sourceGenerator in sourceGenerators)
|
||||
{
|
||||
CompilationInfos.Add(("WebView extraction enabled", "0"));
|
||||
this.generatedSources.AddRange(sourceGenerator.Generate());
|
||||
}
|
||||
|
||||
CompilationInfos.Add(("UseWPF set", fileContent.UseWpf ? "1" : "0"));
|
||||
CompilationInfos.Add(("UseWindowsForms set", fileContent.UseWindowsForms ? "1" : "0"));
|
||||
|
||||
GenerateSourceFileFromImplicitUsings();
|
||||
|
||||
const int align = 6;
|
||||
logger.LogInfo("");
|
||||
logger.LogInfo("Build analysis summary:");
|
||||
logger.LogInfo($"{nonGeneratedSources.Count,align} source files found on the filesystem");
|
||||
logger.LogInfo($"{generatedSources.Count,align} source files have been generated");
|
||||
logger.LogInfo($"{allSolutions.Count,align} solution files found on the filesystem");
|
||||
logger.LogInfo($"{allProjects.Count,align} project files found on the filesystem");
|
||||
logger.LogInfo($"{fileProvider.Solutions.Count,align} solution files found on the filesystem");
|
||||
logger.LogInfo($"{fileProvider.Projects.Count,align} project files found on the filesystem");
|
||||
logger.LogInfo($"{usedReferences.Keys.Count,align} resolved references");
|
||||
logger.LogInfo($"{unresolvedReferences.Count,align} unresolved references");
|
||||
logger.LogInfo($"{conflictedReferences,align} resolved assembly conflicts");
|
||||
@@ -182,8 +179,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
CompilationInfos.AddRange([
|
||||
("Source files on filesystem", nonGeneratedSources.Count.ToString()),
|
||||
("Source files generated", generatedSources.Count.ToString()),
|
||||
("Solution files on filesystem", allSolutions.Count.ToString()),
|
||||
("Project files on filesystem", allProjects.Count.ToString()),
|
||||
("Solution files on filesystem", fileProvider.Solutions.Count.ToString()),
|
||||
("Project files on filesystem", fileProvider.Projects.Count.ToString()),
|
||||
("Resolved references", usedReferences.Keys.Count.ToString()),
|
||||
("Unresolved references", unresolvedReferences.Count.ToString()),
|
||||
("Resolved assembly conflicts", conflictedReferences.ToString()),
|
||||
@@ -229,11 +226,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private void RemoveNugetAnalyzerReferences()
|
||||
{
|
||||
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
|
||||
if (packageFolder == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant();
|
||||
|
||||
foreach (var filename in usedReferences.Keys)
|
||||
{
|
||||
@@ -256,7 +249,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
if (isInAnalyzersFolder)
|
||||
{
|
||||
usedReferences.Remove(filename);
|
||||
logger.LogInfo($"Removed analyzer reference {filename}");
|
||||
logger.LogDebug($"Removed analyzer reference {filename}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,19 +261,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
if (versionFolders.Length > 1)
|
||||
{
|
||||
var versions = string.Join(", ", versionFolders.Select(d => d.Name));
|
||||
logger.LogInfo($"Found multiple {frameworkType} DLLs in NuGet packages at {frameworkPath}. Using the latest version ({versionFolders[0].Name}) from: {versions}.");
|
||||
logger.LogDebug($"Found multiple {frameworkType} DLLs in NuGet packages at {frameworkPath}. Using the latest version ({versionFolders[0].Name}) from: {versions}.");
|
||||
}
|
||||
|
||||
var selectedFrameworkFolder = versionFolders.FirstOrDefault()?.FullName;
|
||||
if (selectedFrameworkFolder is null)
|
||||
{
|
||||
logger.LogInfo($"Found {frameworkType} DLLs in NuGet packages at {frameworkPath}, but no version folder was found.");
|
||||
logger.LogDebug($"Found {frameworkType} DLLs in NuGet packages at {frameworkPath}, but no version folder was found.");
|
||||
selectedFrameworkFolder = frameworkPath;
|
||||
}
|
||||
|
||||
dllLocations.Add(selectedFrameworkFolder);
|
||||
frameworkLocations.Add(selectedFrameworkFolder);
|
||||
logger.LogInfo($"Found {frameworkType} DLLs in NuGet packages at {selectedFrameworkFolder}.");
|
||||
logger.LogDebug($"Found {frameworkType} DLLs in NuGet packages at {selectedFrameworkFolder}.");
|
||||
}
|
||||
|
||||
private static DirectoryInfo[] GetPackageVersionSubDirectories(string packagePath)
|
||||
@@ -307,7 +300,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var packagesInPrioOrder = FrameworkPackageNames.NetFrameworks;
|
||||
|
||||
var frameworkPaths = packagesInPrioOrder
|
||||
.Select((s, index) => (Index: index, Path: GetPackageDirectory(s, packageDirectory)))
|
||||
.Select((s, index) => (Index: index, Path: GetPackageDirectory(s)))
|
||||
.Where(pair => pair.Path is not null)
|
||||
.ToArray();
|
||||
|
||||
@@ -338,11 +331,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
if (runtimeLocation is null)
|
||||
{
|
||||
logger.LogInfo("No .NET Desktop Runtime location found. Attempting to restore the .NET Framework reference assemblies manually.");
|
||||
|
||||
if (TryRestorePackageManually(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies, null))
|
||||
{
|
||||
runtimeLocation = GetPackageDirectory(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies, missingPackageDirectory);
|
||||
}
|
||||
runtimeLocation = nugetPackageRestorer.TryRestoreLatestNetFrameworkReferenceAssemblies();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,35 +351,25 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private void RemoveNugetPackageReference(string packagePrefix, ISet<AssemblyLookupLocation> dllLocations)
|
||||
{
|
||||
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
|
||||
if (packageFolder == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant();
|
||||
var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
|
||||
var toRemove = dllLocations.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
|
||||
foreach (var path in toRemove)
|
||||
{
|
||||
dllLocations.Remove(path);
|
||||
logger.LogInfo($"Removed reference {path}");
|
||||
logger.LogDebug($"Removed reference {path}");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsAspNetCoreDetected()
|
||||
{
|
||||
return fileContent.IsNewProjectStructureUsed && fileContent.UseAspNetCoreDlls;
|
||||
}
|
||||
|
||||
private void AddAspNetCoreFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
|
||||
{
|
||||
if (!IsAspNetCoreDetected())
|
||||
if (!fileContent.IsAspNetCoreDetected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// First try to find ASP.NET Core assemblies in the NuGet packages
|
||||
if (GetPackageDirectory(FrameworkPackageNames.AspNetCoreFramework, packageDirectory) is string aspNetCorePackage)
|
||||
if (GetPackageDirectory(FrameworkPackageNames.AspNetCoreFramework) is string aspNetCorePackage)
|
||||
{
|
||||
SelectNewestFrameworkPath(aspNetCorePackage, "ASP.NET Core", dllLocations, frameworkLocations);
|
||||
return;
|
||||
@@ -406,165 +385,25 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private void AddMicrosoftWindowsDesktopDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
|
||||
{
|
||||
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework, packageDirectory) is string windowsDesktopApp)
|
||||
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework) is string windowsDesktopApp)
|
||||
{
|
||||
SelectNewestFrameworkPath(windowsDesktopApp, "Windows Desktop App", dllLocations, frameworkLocations);
|
||||
}
|
||||
}
|
||||
|
||||
private string? GetPackageDirectory(string packagePrefix, TemporaryDirectory root)
|
||||
private string? GetPackageDirectory(string packagePrefix)
|
||||
{
|
||||
return new DirectoryInfo(root.DirInfo.FullName)
|
||||
return GetPackageDirectory(packagePrefix, nugetPackageRestorer.PackageDirectory.DirInfo);
|
||||
}
|
||||
|
||||
internal static string? GetPackageDirectory(string packagePrefix, DirectoryInfo root)
|
||||
{
|
||||
return new DirectoryInfo(root.FullName)
|
||||
.EnumerateDirectories(packagePrefix + "*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
|
||||
.FirstOrDefault()?
|
||||
.FullName;
|
||||
}
|
||||
|
||||
private void GenerateSourceFileFromImplicitUsings()
|
||||
{
|
||||
var usings = new HashSet<string>();
|
||||
if (!fileContent.UseImplicitUsings)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Hardcoded values from https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives
|
||||
usings.UnionWith([ "System", "System.Collections.Generic", "System.IO", "System.Linq", "System.Net.Http", "System.Threading",
|
||||
"System.Threading.Tasks" ]);
|
||||
|
||||
if (fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
usings.UnionWith([ "System.Net.Http.Json", "Microsoft.AspNetCore.Builder", "Microsoft.AspNetCore.Hosting",
|
||||
"Microsoft.AspNetCore.Http", "Microsoft.AspNetCore.Routing", "Microsoft.Extensions.Configuration",
|
||||
"Microsoft.Extensions.DependencyInjection", "Microsoft.Extensions.Hosting", "Microsoft.Extensions.Logging" ]);
|
||||
}
|
||||
|
||||
if (fileContent.UseWindowsForms)
|
||||
{
|
||||
usings.UnionWith(["System.Drawing", "System.Windows.Forms"]);
|
||||
}
|
||||
|
||||
usings.UnionWith(fileContent.CustomImplicitUsings);
|
||||
|
||||
logger.LogInfo($"Generating source file for implicit usings. Namespaces: {string.Join(", ", usings.OrderBy(u => u))}");
|
||||
|
||||
if (usings.Count > 0)
|
||||
{
|
||||
var tempDir = GetTemporaryWorkingDirectory("implicitUsings");
|
||||
var path = Path.Combine(tempDir, "GlobalUsings.g.cs");
|
||||
using (var writer = new StreamWriter(path))
|
||||
{
|
||||
writer.WriteLine("// <auto-generated/>");
|
||||
writer.WriteLine("");
|
||||
|
||||
foreach (var u in usings.OrderBy(u => u))
|
||||
{
|
||||
writer.WriteLine($"global using global::{u};");
|
||||
}
|
||||
}
|
||||
|
||||
this.generatedSources.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateSourceFilesFromWebViews(List<FileInfo> allFiles)
|
||||
{
|
||||
var views = allFiles.SelectFileNamesByExtension(".cshtml", ".razor").ToArray();
|
||||
if (views.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInfo($"Found {views.Length} cshtml and razor files.");
|
||||
|
||||
if (!IsAspNetCoreDetected())
|
||||
{
|
||||
logger.LogInfo("Generating source files from cshtml files is only supported for new (SDK-style) project files");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInfo("Generating source files from cshtml and razor files...");
|
||||
|
||||
var sdk = new Sdk(dotnet).GetNewestSdk();
|
||||
if (sdk != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var razor = new Razor(sdk, dotnet, logger);
|
||||
var targetDir = GetTemporaryWorkingDirectory("razor");
|
||||
var generatedFiles = razor.GenerateFiles(views, usedReferences.Keys, targetDir);
|
||||
this.generatedSources.AddRange(generatedFiles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// It's okay, we tried our best to generate source files from cshtml files.
|
||||
logger.LogInfo($"Failed to generate source files from cshtml files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<FileInfo> GetAllFiles()
|
||||
{
|
||||
IEnumerable<FileInfo> files = sourceDir.GetFiles("*.*", new EnumerationOptions { RecurseSubdirectories = true });
|
||||
|
||||
if (dotnetPath != null)
|
||||
{
|
||||
files = files.Where(f => !f.FullName.StartsWith(dotnetPath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
files = files.Where(f =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (f.Exists)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.LogWarning($"File {f.FullName} could not be processed.");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning($"File {f.FullName} could not be processed: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
files = new FilePathFilter(sourceDir, logger).Filter(files);
|
||||
return files;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a unique temp directory for the packages associated
|
||||
/// with this source tree. Use a SHA1 of the directory name.
|
||||
/// </summary>
|
||||
/// <returns>The full path of the temp directory.</returns>
|
||||
private static string ComputeTempDirectory(string srcDir, string subfolderName)
|
||||
{
|
||||
var bytes = Encoding.Unicode.GetBytes(srcDir);
|
||||
var sha = SHA1.HashData(bytes);
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in sha.Take(8))
|
||||
sb.AppendFormat("{0:x2}", b);
|
||||
|
||||
return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out var _), sb.ToString(), subfolderName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary directory with the given subfolder name.
|
||||
/// The created directory might be inside the repo folder, and it is deleted when the object is disposed.
|
||||
/// </summary>
|
||||
/// <param name="subfolder"></param>
|
||||
/// <returns></returns>
|
||||
private string GetTemporaryWorkingDirectory(string subfolder)
|
||||
{
|
||||
var temp = Path.Combine(tempWorkingDirectory.ToString(), subfolder);
|
||||
Directory.CreateDirectory(temp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves conflicts between all of the resolved references.
|
||||
/// If the same assembly name is duplicated with different versions,
|
||||
@@ -616,7 +455,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
if (resolvedInfo.Version != r.Version || resolvedInfo.NetCoreVersion != r.NetCoreVersion)
|
||||
{
|
||||
var asm = resolvedInfo.Id + (resolvedInfo.NetCoreVersion is null ? "" : $" (.NET Core {resolvedInfo.NetCoreVersion})");
|
||||
logger.LogInfo($"Resolved {r.Id} as {asm}");
|
||||
logger.LogDebug($"Resolved {r.Id} as {asm}");
|
||||
|
||||
++conflictedReferences;
|
||||
}
|
||||
@@ -674,7 +513,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private void AnalyseSolutions(IEnumerable<string> solutions)
|
||||
{
|
||||
Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = threads }, solutionFile =>
|
||||
Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = Threads }, solutionFile =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -723,29 +562,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose(TemporaryDirectory? dir, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
dir?.Dispose();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger.LogInfo($"Couldn't delete {name} directory {exc.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(packageDirectory, "package");
|
||||
Dispose(legacyPackageDirectory, "legacy package");
|
||||
Dispose(missingPackageDirectory, "missing package");
|
||||
if (cleanupTempWorkingDirectory)
|
||||
{
|
||||
Dispose(tempWorkingDirectory, "temporary working");
|
||||
}
|
||||
|
||||
tempWorkingDirectory?.Dispose();
|
||||
diagnosticsWriter?.Dispose();
|
||||
nugetPackageRestorer?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private void Info()
|
||||
{
|
||||
var res = dotnetCliInvoker.RunCommand("--info");
|
||||
var res = dotnetCliInvoker.RunCommand("--info", silent: false);
|
||||
if (!res)
|
||||
{
|
||||
throw new Exception($"{dotnetCliInvoker.Exec} --info failed.");
|
||||
@@ -91,13 +91,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return dotnetCliInvoker.RunCommand(args);
|
||||
}
|
||||
|
||||
public IList<string> GetListedRuntimes() => GetResultList("--list-runtimes");
|
||||
public IList<string> GetListedRuntimes() => GetResultList("--list-runtimes", null, false);
|
||||
|
||||
public IList<string> GetListedSdks() => GetResultList("--list-sdks");
|
||||
public IList<string> GetListedSdks() => GetResultList("--list-sdks", null, false);
|
||||
|
||||
private IList<string> GetResultList(string args)
|
||||
private IList<string> GetResultList(string args, string? workingDirectory = null, bool silent = true)
|
||||
{
|
||||
if (dotnetCliInvoker.RunCommand(args, out var results))
|
||||
if (dotnetCliInvoker.RunCommand(args, workingDirectory, out var results, silent))
|
||||
{
|
||||
return results;
|
||||
}
|
||||
@@ -111,7 +111,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return dotnetCliInvoker.RunCommand(args);
|
||||
}
|
||||
|
||||
public IList<string> GetNugetFeeds(string nugetConfig) => GetResultList($"nuget list source --format Short --configfile \"{nugetConfig}\"");
|
||||
private const string nugetListSourceCommand = "nuget list source --format Short";
|
||||
|
||||
public IList<string> GetNugetFeeds(string nugetConfig)
|
||||
{
|
||||
logger.LogInfo($"Getting Nuget feeds from '{nugetConfig}'...");
|
||||
return GetResultList($"{nugetListSourceCommand} --configfile \"{nugetConfig}\"");
|
||||
}
|
||||
|
||||
public IList<string> GetNugetFeedsFromFolder(string folderPath)
|
||||
{
|
||||
logger.LogInfo($"Getting Nuget feeds in folder '{folderPath}'...");
|
||||
return GetResultList(nugetListSourceCommand, folderPath);
|
||||
}
|
||||
|
||||
// The version number should be kept in sync with the version .NET version used for building the application.
|
||||
public const string LatestDotNetSdkVersion = "8.0.101";
|
||||
@@ -304,4 +316,4 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
this.Exec = exec;
|
||||
}
|
||||
|
||||
private ProcessStartInfo MakeDotnetStartInfo(string args)
|
||||
private ProcessStartInfo MakeDotnetStartInfo(string args, string? workingDirectory)
|
||||
{
|
||||
var startInfo = new ProcessStartInfo(Exec, args)
|
||||
{
|
||||
@@ -29,6 +29,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(workingDirectory))
|
||||
{
|
||||
startInfo.WorkingDirectory = workingDirectory;
|
||||
}
|
||||
// Set the .NET CLI language to English to avoid localized output.
|
||||
startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"] = "en";
|
||||
startInfo.EnvironmentVariables["MSBUILDDISABLENODEREUSE"] = "1";
|
||||
@@ -36,26 +40,30 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return startInfo;
|
||||
}
|
||||
|
||||
private bool RunCommandAux(string args, out IList<string> output)
|
||||
private bool RunCommandAux(string args, string? workingDirectory, out IList<string> output, bool silent)
|
||||
{
|
||||
logger.LogInfo($"Running {Exec} {args}");
|
||||
var pi = MakeDotnetStartInfo(args);
|
||||
var dirLog = string.IsNullOrWhiteSpace(workingDirectory) ? "" : $" in {workingDirectory}";
|
||||
logger.LogInfo($"Running {Exec} {args}{dirLog}");
|
||||
var pi = MakeDotnetStartInfo(args, workingDirectory);
|
||||
var threadId = Environment.CurrentManagedThreadId;
|
||||
void onOut(string s) => logger.LogInfo(s, threadId);
|
||||
void onOut(string s) => logger.Log(silent ? Severity.Debug : Severity.Info, s, threadId);
|
||||
void onError(string s) => logger.LogError(s, threadId);
|
||||
var exitCode = pi.ReadOutput(out output, onOut, onError);
|
||||
if (exitCode != 0)
|
||||
{
|
||||
logger.LogError($"Command {Exec} {args} failed with exit code {exitCode}");
|
||||
logger.LogError($"Command {Exec} {args}{dirLog} failed with exit code {exitCode}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RunCommand(string args) =>
|
||||
RunCommandAux(args, out _);
|
||||
public bool RunCommand(string args, bool silent) =>
|
||||
RunCommandAux(args, null, out _, silent);
|
||||
|
||||
public bool RunCommand(string args, out IList<string> output) =>
|
||||
RunCommandAux(args, out output);
|
||||
public bool RunCommand(string args, out IList<string> output, bool silent) =>
|
||||
RunCommandAux(args, null, out output, silent);
|
||||
|
||||
public bool RunCommand(string args, string? workingDirectory, out IList<string> output, bool silent) =>
|
||||
RunCommandAux(args, workingDirectory, out output, silent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,28 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
public const string NugetFeedResponsivenessInitialTimeout = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_TIMEOUT";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how many requests to make to the NuGet feed to check its responsiveness.
|
||||
/// Specifies the timeout (as an integer) in milliseconds for the initial check of fallback NuGet feeds responsiveness. The value is then doubled for each subsequent check.
|
||||
/// This is primarily used in testing.
|
||||
/// </summary>
|
||||
internal const string NugetFeedResponsivenessInitialTimeoutForFallback = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_TIMEOUT";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how many requests to make to the NuGet feeds to check their responsiveness.
|
||||
/// </summary>
|
||||
public const string NugetFeedResponsivenessRequestCount = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_LIMIT";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how many requests to make to the fallback NuGet feeds to check their responsiveness.
|
||||
/// This is primarily used in testing.
|
||||
/// </summary>
|
||||
internal const string NugetFeedResponsivenessRequestCountForFallback = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_LIMIT";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the NuGet feeds to use for fallback Nuget dependency fetching. The value is a space-separated list of feed URLs.
|
||||
/// The default value is `https://api.nuget.org/v3/index.json`.
|
||||
/// </summary>
|
||||
public const string FallbackNugetFeeds = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_FALLBACK";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the location of the diagnostic directory.
|
||||
/// </summary>
|
||||
|
||||
@@ -50,6 +50,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAspNetCoreDetected
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsNewProjectStructureUsed && UseAspNetCoreDlls;
|
||||
}
|
||||
}
|
||||
|
||||
private bool useImplicitUsings = false;
|
||||
|
||||
public bool UseImplicitUsings
|
||||
|
||||
@@ -14,20 +14,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
public static IEnumerable<FileInfo> SelectRootFiles(this IEnumerable<FileInfo> files, DirectoryInfo dir) =>
|
||||
files.Where(file => file.DirectoryName == dir.FullName);
|
||||
|
||||
internal static IEnumerable<FileInfo> SelectSmallFiles(this IEnumerable<FileInfo> files, ILogger logger)
|
||||
{
|
||||
const int oneMb = 1_048_576;
|
||||
return files.Where(file =>
|
||||
{
|
||||
if (file.Length > oneMb)
|
||||
{
|
||||
logger.LogDebug($"Skipping {file.FullName} because it is bigger than 1MB.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static IEnumerable<string> SelectFileNamesByExtension(this IEnumerable<FileInfo> files, params string[] extensions) =>
|
||||
files.SelectFilesAux(fi => extensions.Contains(fi.Extension));
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Policy;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
public class FileProvider
|
||||
{
|
||||
private static readonly HashSet<string> binaryFileExtensions = [".dll", ".exe"]; // TODO: add more binary file extensions.
|
||||
|
||||
private readonly ILogger logger;
|
||||
private readonly FileInfo[] all;
|
||||
private readonly Lazy<FileInfo[]> allNonBinary;
|
||||
private readonly Lazy<string[]> smallNonBinary;
|
||||
private readonly Lazy<string[]> sources;
|
||||
private readonly Lazy<string[]> projects;
|
||||
private readonly Lazy<string[]> solutions;
|
||||
private readonly Lazy<string[]> dlls;
|
||||
private readonly Lazy<string[]> nugetConfigs;
|
||||
private readonly Lazy<string[]> globalJsons;
|
||||
private readonly Lazy<string[]> razorViews;
|
||||
private readonly Lazy<string?> rootNugetConfig;
|
||||
|
||||
public FileProvider(DirectoryInfo sourceDir, ILogger logger)
|
||||
{
|
||||
SourceDir = sourceDir;
|
||||
this.logger = logger;
|
||||
|
||||
all = GetAllFiles();
|
||||
allNonBinary = new Lazy<FileInfo[]>(() => all.Where(f => !binaryFileExtensions.Contains(f.Extension.ToLowerInvariant())).ToArray());
|
||||
smallNonBinary = new Lazy<string[]>(() =>
|
||||
{
|
||||
var ret = SelectSmallFiles(allNonBinary.Value).SelectFileNames().ToArray();
|
||||
logger.LogInfo($"Found {ret.Length} small non-binary files in {SourceDir}.");
|
||||
return ret;
|
||||
});
|
||||
sources = new Lazy<string[]>(() => SelectTextFileNamesByExtension("source", ".cs"));
|
||||
projects = new Lazy<string[]>(() => SelectTextFileNamesByExtension("project", ".csproj"));
|
||||
solutions = new Lazy<string[]>(() => SelectTextFileNamesByExtension("solution", ".sln"));
|
||||
dlls = new Lazy<string[]>(() => SelectBinaryFileNamesByExtension("DLL", ".dll"));
|
||||
nugetConfigs = new Lazy<string[]>(() => allNonBinary.Value.SelectFileNamesByName("nuget.config").ToArray());
|
||||
globalJsons = new Lazy<string[]>(() => allNonBinary.Value.SelectFileNamesByName("global.json").ToArray());
|
||||
razorViews = new Lazy<string[]>(() => SelectTextFileNamesByExtension("razor view", ".cshtml", ".razor"));
|
||||
|
||||
rootNugetConfig = new Lazy<string?>(() => all.SelectRootFiles(SourceDir).SelectFileNamesByName("nuget.config").FirstOrDefault());
|
||||
}
|
||||
|
||||
private string[] SelectTextFileNamesByExtension(string filetype, params string[] extensions)
|
||||
{
|
||||
var ret = allNonBinary.Value.SelectFileNamesByExtension(extensions).ToArray();
|
||||
logger.LogInfo($"Found {ret.Length} {filetype} files in {SourceDir}.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
private string[] SelectBinaryFileNamesByExtension(string filetype, params string[] extensions)
|
||||
{
|
||||
var ret = all.SelectFileNamesByExtension(extensions).ToArray();
|
||||
logger.LogInfo($"Found {ret.Length} {filetype} files in {SourceDir}.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
private IEnumerable<FileInfo> SelectSmallFiles(IEnumerable<FileInfo> files)
|
||||
{
|
||||
const int oneMb = 1_048_576;
|
||||
return files.Where(file =>
|
||||
{
|
||||
if (file.Length > oneMb)
|
||||
{
|
||||
logger.LogDebug($"Skipping {file.FullName} because it is bigger than 1MB.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private FileInfo[] GetAllFiles()
|
||||
{
|
||||
logger.LogInfo($"Finding files in {SourceDir}...");
|
||||
var files = SourceDir.GetFiles("*.*", new EnumerationOptions { RecurseSubdirectories = true });
|
||||
|
||||
var filteredFiles = files.Where(f =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (f.Exists)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.LogWarning($"File {f.FullName} could not be processed.");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning($"File {f.FullName} could not be processed: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
var allFiles = new FilePathFilter(SourceDir, logger).Filter(filteredFiles).ToArray();
|
||||
|
||||
logger.LogInfo($"Found {allFiles.Length} files in {SourceDir}.");
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
public DirectoryInfo SourceDir { get; }
|
||||
public IEnumerable<string> SmallNonBinary => smallNonBinary.Value;
|
||||
public IEnumerable<string> Sources => sources.Value;
|
||||
public ICollection<string> Projects => projects.Value;
|
||||
public ICollection<string> Solutions => solutions.Value;
|
||||
public IEnumerable<string> Dlls => dlls.Value;
|
||||
public ICollection<string> NugetConfigs => nugetConfigs.Value;
|
||||
public string? RootNugetConfig => rootNugetConfig.Value;
|
||||
public IEnumerable<string> GlobalJsons => globalJsons.Value;
|
||||
public ICollection<string> RazorViews => razorViews.Value;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
IList<string> GetListedSdks();
|
||||
bool Exec(string execArgs);
|
||||
IList<string> GetNugetFeeds(string nugetConfig);
|
||||
IList<string> GetNugetFeedsFromFolder(string folderPath);
|
||||
}
|
||||
|
||||
public record class RestoreSettings(string File, string PackageDirectory, bool ForceDotnetRefAssemblyFetching, string? PathToNugetConfig = null, bool ForceReevaluation = false);
|
||||
|
||||
@@ -11,13 +11,22 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
/// <summary>
|
||||
/// Execute `dotnet <args>` and return true if the command succeeded, otherwise false.
|
||||
/// If `silent` is true the output of the command is logged as `debug` otherwise as `info`.
|
||||
/// </summary>
|
||||
bool RunCommand(string args);
|
||||
bool RunCommand(string args, bool silent = true);
|
||||
|
||||
/// <summary>
|
||||
/// Execute `dotnet <args>` and return true if the command succeeded, otherwise false.
|
||||
/// The output of the command is returned in `output`.
|
||||
/// If `silent` is true the output of the command is logged as `debug` otherwise as `info`.
|
||||
/// </summary>
|
||||
bool RunCommand(string args, out IList<string> output);
|
||||
bool RunCommand(string args, out IList<string> output, bool silent = true);
|
||||
|
||||
/// <summary>
|
||||
/// Execute `dotnet <args>` in `<workingDirectory>` and return true if the command succeeded, otherwise false.
|
||||
/// The output of the command is returned in `output`.
|
||||
/// If `silent` is true the output of the command is logged as `debug` otherwise as `info`.
|
||||
/// </summary>
|
||||
bool RunCommand(string args, string? workingDirectory, out IList<string> output, bool silent = true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ using Semmle.Util;
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
/// <summary>
|
||||
/// Manage the downloading of NuGet packages.
|
||||
/// Manage the downloading of NuGet packages with nuget.exe.
|
||||
/// Locates packages in a source tree and downloads all of the
|
||||
/// referenced assemblies to a temp folder.
|
||||
/// </summary>
|
||||
internal class NugetPackages : IDisposable
|
||||
internal class NugetExeWrapper : IDisposable
|
||||
{
|
||||
private readonly string? nugetExe;
|
||||
private readonly Util.Logging.ILogger logger;
|
||||
@@ -37,7 +37,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// <summary>
|
||||
/// Create the package manager for a specified source tree.
|
||||
/// </summary>
|
||||
public NugetPackages(string sourceDir, TemporaryDirectory packageDirectory, Util.Logging.ILogger logger)
|
||||
public NugetExeWrapper(string sourceDir, TemporaryDirectory packageDirectory, Util.Logging.ILogger logger)
|
||||
{
|
||||
this.packageDirectory = packageDirectory;
|
||||
this.logger = logger;
|
||||
@@ -175,7 +175,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
};
|
||||
|
||||
var threadId = Environment.CurrentManagedThreadId;
|
||||
void onOut(string s) => logger.LogInfo(s, threadId);
|
||||
void onOut(string s) => logger.LogDebug(s, threadId);
|
||||
void onError(string s) => logger.LogError(s, threadId);
|
||||
var exitCode = pi.ReadOutput(out var _, onOut, onError);
|
||||
if (exitCode != 0)
|
||||
@@ -235,7 +235,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
};
|
||||
|
||||
var threadId = Environment.CurrentManagedThreadId;
|
||||
void onOut(string s) => logger.LogInfo(s, threadId);
|
||||
void onOut(string s) => logger.LogDebug(s, threadId);
|
||||
void onError(string s) => logger.LogError(s, threadId);
|
||||
pi.ReadOutput(out stdout, onOut, onError);
|
||||
}
|
||||
@@ -243,7 +243,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
private void AddDefaultPackageSource(string nugetConfig)
|
||||
{
|
||||
logger.LogInfo("Adding default package source...");
|
||||
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source https://api.nuget.org/v3/index.json -ConfigFile \"{nugetConfig}\"", out var _);
|
||||
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {NugetPackageRestorer.PublicNugetOrgFeed} -ConfigFile \"{nugetConfig}\"", out var _);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -3,34 +3,84 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
public sealed partial class DependencyManager
|
||||
internal sealed partial class NugetPackageRestorer : IDisposable
|
||||
{
|
||||
private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<string> allProjects, IEnumerable<string> allSolutions, HashSet<AssemblyLookupLocation> dllLocations)
|
||||
internal const string PublicNugetOrgFeed = "https://api.nuget.org/v3/index.json";
|
||||
|
||||
private readonly FileProvider fileProvider;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly IDotNet dotnet;
|
||||
private readonly IDiagnosticsWriter diagnosticsWriter;
|
||||
private readonly TemporaryDirectory legacyPackageDirectory;
|
||||
private readonly TemporaryDirectory missingPackageDirectory;
|
||||
private readonly ILogger logger;
|
||||
private readonly ICompilationInfoContainer compilationInfoContainer;
|
||||
|
||||
public TemporaryDirectory PackageDirectory { get; }
|
||||
|
||||
public NugetPackageRestorer(
|
||||
FileProvider fileProvider,
|
||||
FileContent fileContent,
|
||||
IDotNet dotnet,
|
||||
IDiagnosticsWriter diagnosticsWriter,
|
||||
ILogger logger,
|
||||
ICompilationInfoContainer compilationInfoContainer)
|
||||
{
|
||||
this.fileProvider = fileProvider;
|
||||
this.fileContent = fileContent;
|
||||
this.dotnet = dotnet;
|
||||
this.diagnosticsWriter = diagnosticsWriter;
|
||||
this.logger = logger;
|
||||
this.compilationInfoContainer = compilationInfoContainer;
|
||||
|
||||
PackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath(fileProvider.SourceDir.FullName, "packages"), "package", logger);
|
||||
legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath(fileProvider.SourceDir.FullName, "legacypackages"), "legacy package", logger);
|
||||
missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath(fileProvider.SourceDir.FullName, "missingpackages"), "missing package", logger);
|
||||
}
|
||||
|
||||
public string? TryRestoreLatestNetFrameworkReferenceAssemblies()
|
||||
{
|
||||
if (TryRestorePackageManually(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies))
|
||||
{
|
||||
return DependencyManager.GetPackageDirectory(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies, missingPackageDirectory.DirInfo);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public HashSet<AssemblyLookupLocation> Restore()
|
||||
{
|
||||
var assemblyLookupLocations = new HashSet<AssemblyLookupLocation>();
|
||||
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBoolean(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
|
||||
try
|
||||
{
|
||||
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBoolean(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
|
||||
if (checkNugetFeedResponsiveness && !CheckFeeds(allNonBinaryFiles))
|
||||
if (checkNugetFeedResponsiveness && !CheckFeeds())
|
||||
{
|
||||
DownloadMissingPackages(allNonBinaryFiles, dllLocations, withNugetConfig: false);
|
||||
return;
|
||||
// todo: we could also check the reachability of the inherited nuget feeds, but to use those in the fallback we would need to handle authentication too.
|
||||
var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds();
|
||||
return unresponsiveMissingPackageLocation is null
|
||||
? []
|
||||
: [unresponsiveMissingPackageLocation];
|
||||
}
|
||||
|
||||
using (var nuget = new NugetPackages(sourceDir.FullName, legacyPackageDirectory, logger))
|
||||
using (var nuget = new NugetExeWrapper(fileProvider.SourceDir.FullName, legacyPackageDirectory, logger))
|
||||
{
|
||||
var count = nuget.InstallPackages();
|
||||
|
||||
if (nuget.PackageCount > 0)
|
||||
{
|
||||
CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString()));
|
||||
CompilationInfos.Add(("Successfully restored packages.config files", count.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Successfully restored packages.config files", count.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,27 +105,60 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
|
||||
nugetPackageDllPaths.ExceptWith(excludedPaths);
|
||||
dllLocations.UnionWith(nugetPackageDllPaths.Select(p => new AssemblyLookupLocation(p)));
|
||||
assemblyLookupLocations.UnionWith(nugetPackageDllPaths.Select(p => new AssemblyLookupLocation(p)));
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger.LogError($"Failed to restore Nuget packages with nuget.exe: {exc.Message}");
|
||||
}
|
||||
|
||||
var restoredProjects = RestoreSolutions(allSolutions, out var assets1);
|
||||
var projects = allProjects.Except(restoredProjects);
|
||||
var restoredProjects = RestoreSolutions(out var assets1);
|
||||
var projects = fileProvider.Projects.Except(restoredProjects);
|
||||
RestoreProjects(projects, out var assets2);
|
||||
|
||||
var dependencies = Assets.GetCompilationDependencies(logger, assets1.Union(assets2));
|
||||
|
||||
var paths = dependencies
|
||||
.Paths
|
||||
.Select(d => Path.Combine(packageDirectory.DirInfo.FullName, d))
|
||||
.Select(d => Path.Combine(PackageDirectory.DirInfo.FullName, d))
|
||||
.ToList();
|
||||
dllLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p)));
|
||||
assemblyLookupLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p)));
|
||||
|
||||
LogAllUnusedPackages(dependencies);
|
||||
DownloadMissingPackages(allNonBinaryFiles, dllLocations);
|
||||
|
||||
var missingPackageLocation = checkNugetFeedResponsiveness
|
||||
? DownloadMissingPackagesFromSpecificFeeds()
|
||||
: DownloadMissingPackages();
|
||||
|
||||
if (missingPackageLocation is not null)
|
||||
{
|
||||
assemblyLookupLocations.Add(missingPackageLocation);
|
||||
}
|
||||
return assemblyLookupLocations;
|
||||
}
|
||||
|
||||
private List<string> GetReachableFallbackNugetFeeds()
|
||||
{
|
||||
var fallbackFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.FallbackNugetFeeds).ToHashSet();
|
||||
if (fallbackFeeds.Count == 0)
|
||||
{
|
||||
fallbackFeeds.Add(PublicNugetOrgFeed);
|
||||
logger.LogInfo($"No fallback Nuget feeds specified. Using default feed: {PublicNugetOrgFeed}");
|
||||
}
|
||||
|
||||
logger.LogInfo($"Checking fallback Nuget feed reachability on feeds: {string.Join(", ", fallbackFeeds.OrderBy(f => f))}");
|
||||
var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: true);
|
||||
var reachableFallbackFeeds = fallbackFeeds.Where(feed => IsFeedReachable(feed, initialTimeout, tryCount, allowExceptions: false)).ToList();
|
||||
if (reachableFallbackFeeds.Count == 0)
|
||||
{
|
||||
logger.LogWarning("No fallback Nuget feeds are reachable.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInfo($"Reachable fallback Nuget feeds: {string.Join(", ", reachableFallbackFeeds.OrderBy(f => f))}");
|
||||
}
|
||||
|
||||
return reachableFallbackFeeds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,16 +169,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// Populates assets with the relative paths to the assets files generated by the restore.
|
||||
/// Returns a list of projects that are up to date with respect to restore.
|
||||
/// </summary>
|
||||
/// <param name="solutions">A list of paths to solution files.</param>
|
||||
private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out IEnumerable<string> assets)
|
||||
private IEnumerable<string> RestoreSolutions(out IEnumerable<string> assets)
|
||||
{
|
||||
var successCount = 0;
|
||||
var nugetSourceFailures = 0;
|
||||
var assetFiles = new List<string>();
|
||||
var projects = solutions.SelectMany(solution =>
|
||||
var projects = fileProvider.Solutions.SelectMany(solution =>
|
||||
{
|
||||
logger.LogInfo($"Restoring solution {solution}...");
|
||||
var res = dotnet.Restore(new(solution, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
|
||||
var res = dotnet.Restore(new(solution, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
|
||||
if (res.Success)
|
||||
{
|
||||
successCount++;
|
||||
@@ -108,9 +190,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return res.RestoredProjects;
|
||||
}).ToList();
|
||||
assets = assetFiles;
|
||||
CompilationInfos.Add(("Successfully restored solution files", successCount.ToString()));
|
||||
CompilationInfos.Add(("Failed solution restore with package source error", nugetSourceFailures.ToString()));
|
||||
CompilationInfos.Add(("Restored projects through solution files", projects.Count.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Successfully restored solution files", successCount.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Failed solution restore with package source error", nugetSourceFailures.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Restored projects through solution files", projects.Count.ToString()));
|
||||
return projects;
|
||||
}
|
||||
|
||||
@@ -126,10 +208,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var nugetSourceFailures = 0;
|
||||
var assetFiles = new List<string>();
|
||||
var sync = new object();
|
||||
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = threads }, project =>
|
||||
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = DependencyManager.Threads }, project =>
|
||||
{
|
||||
logger.LogInfo($"Restoring project {project}...");
|
||||
var res = dotnet.Restore(new(project, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
|
||||
var res = dotnet.Restore(new(project, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
|
||||
lock (sync)
|
||||
{
|
||||
if (res.Success)
|
||||
@@ -144,13 +226,25 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
});
|
||||
assets = assetFiles;
|
||||
CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
|
||||
CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
|
||||
}
|
||||
|
||||
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<AssemblyLookupLocation> dllLocations, bool withNugetConfig = true)
|
||||
private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds()
|
||||
{
|
||||
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(packageDirectory.DirInfo);
|
||||
var reachableFallbackFeeds = GetReachableFallbackNugetFeeds();
|
||||
if (reachableFallbackFeeds.Count > 0)
|
||||
{
|
||||
return DownloadMissingPackages(fallbackNugetFeeds: reachableFallbackFeeds);
|
||||
}
|
||||
|
||||
logger.LogWarning("Skipping download of missing packages from specific feeds as no fallback Nuget feeds are reachable.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private AssemblyLookupLocation? DownloadMissingPackages(IEnumerable<string>? fallbackNugetFeeds = null)
|
||||
{
|
||||
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(PackageDirectory.DirInfo);
|
||||
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();
|
||||
|
||||
var notYetDownloadedPackages = new HashSet<PackageReference>(fileContent.AllPackages);
|
||||
@@ -165,7 +259,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (notYetDownloadedPackages.Count == 0)
|
||||
{
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
var multipleVersions = notYetDownloadedPackages
|
||||
@@ -181,18 +275,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
|
||||
logger.LogInfo($"Found {notYetDownloadedPackages.Count} packages that are not yet restored");
|
||||
var nugetConfig = withNugetConfig
|
||||
? GetNugetConfig(allFiles)
|
||||
: null;
|
||||
using var tempDir = new TemporaryDirectory(ComputeTempDirectoryPath(fileProvider.SourceDir.FullName, "nugetconfig"), "generated nuget config", logger);
|
||||
var nugetConfig = fallbackNugetFeeds is null
|
||||
? GetNugetConfig()
|
||||
: CreateFallbackNugetConfig(fallbackNugetFeeds, tempDir.DirInfo.FullName);
|
||||
|
||||
CompilationInfos.Add(("Fallback nuget restore", notYetDownloadedPackages.Count.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Fallback nuget restore", notYetDownloadedPackages.Count.ToString()));
|
||||
|
||||
var successCount = 0;
|
||||
var sync = new object();
|
||||
|
||||
Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = threads }, package =>
|
||||
Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = DependencyManager.Threads }, package =>
|
||||
{
|
||||
var success = TryRestorePackageManually(package.Name, nugetConfig, package.PackageReferenceSource);
|
||||
var success = TryRestorePackageManually(package.Name, nugetConfig, package.PackageReferenceSource, tryWithoutNugetConfig: fallbackNugetFeeds is null);
|
||||
if (!success)
|
||||
{
|
||||
return;
|
||||
@@ -204,24 +299,40 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
});
|
||||
|
||||
CompilationInfos.Add(("Successfully ran fallback nuget restore", successCount.ToString()));
|
||||
compilationInfoContainer.CompilationInfos.Add(("Successfully ran fallback nuget restore", successCount.ToString()));
|
||||
|
||||
dllLocations.Add(missingPackageDirectory.DirInfo.FullName);
|
||||
return missingPackageDirectory.DirInfo.FullName;
|
||||
}
|
||||
|
||||
private string[] GetAllNugetConfigs(List<FileInfo> allFiles) => allFiles.SelectFileNamesByName("nuget.config").ToArray();
|
||||
|
||||
private string? GetNugetConfig(List<FileInfo> allFiles)
|
||||
private string? CreateFallbackNugetConfig(IEnumerable<string> fallbackNugetFeeds, string folderPath)
|
||||
{
|
||||
var nugetConfigs = GetAllNugetConfigs(allFiles);
|
||||
var sb = new StringBuilder();
|
||||
fallbackNugetFeeds.ForEach((feed, index) => sb.AppendLine($"<add key=\"feed{index}\" value=\"{feed}\" />"));
|
||||
|
||||
var nugetConfigPath = Path.Combine(folderPath, "nuget.config");
|
||||
logger.LogInfo($"Creating fallback nuget.config file {nugetConfigPath}.");
|
||||
File.WriteAllText(nugetConfigPath,
|
||||
$"""
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
{sb}
|
||||
</packageSources>
|
||||
</configuration>
|
||||
""");
|
||||
|
||||
return nugetConfigPath;
|
||||
}
|
||||
|
||||
private string? GetNugetConfig()
|
||||
{
|
||||
var nugetConfigs = fileProvider.NugetConfigs;
|
||||
string? nugetConfig;
|
||||
if (nugetConfigs.Length > 1)
|
||||
if (nugetConfigs.Count > 1)
|
||||
{
|
||||
logger.LogInfo($"Found multiple nuget.config files: {string.Join(", ", nugetConfigs)}.");
|
||||
nugetConfig = allFiles
|
||||
.SelectRootFiles(sourceDir)
|
||||
.SelectFileNamesByName("nuget.config")
|
||||
.FirstOrDefault();
|
||||
nugetConfig = fileProvider.RootNugetConfig;
|
||||
if (nugetConfig == null)
|
||||
{
|
||||
logger.LogInfo("Could not find a top-level nuget.config file.");
|
||||
@@ -250,13 +361,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
allPackageDirectories
|
||||
.Where(package => !dependencies.Packages.Contains(package))
|
||||
.Order()
|
||||
.ForEach(package => logger.LogInfo($"Unused package: {package}"));
|
||||
.ForEach(package => logger.LogDebug($"Unused package: {package}"));
|
||||
}
|
||||
|
||||
|
||||
private ICollection<string> GetAllPackageDirectories()
|
||||
{
|
||||
return new DirectoryInfo(packageDirectory.DirInfo.FullName)
|
||||
return new DirectoryInfo(PackageDirectory.DirInfo.FullName)
|
||||
.EnumerateDirectories("*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
|
||||
.Select(d => d.Name)
|
||||
.ToList();
|
||||
@@ -298,10 +408,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
.Select(d => Path.GetFileName(d).ToLowerInvariant());
|
||||
}
|
||||
|
||||
private bool TryRestorePackageManually(string package, string? nugetConfig, PackageReferenceSource packageReferenceSource = PackageReferenceSource.SdkCsProj)
|
||||
private bool TryRestorePackageManually(string package, string? nugetConfig = null, PackageReferenceSource packageReferenceSource = PackageReferenceSource.SdkCsProj, bool tryWithoutNugetConfig = true)
|
||||
{
|
||||
logger.LogInfo($"Restoring package {package}...");
|
||||
using var tempDir = new TemporaryDirectory(ComputeTempDirectory(package, "missingpackages_workingdir"));
|
||||
using var tempDir = new TemporaryDirectory(
|
||||
ComputeTempDirectoryPath(package, "missingpackages_workingdir"), "missing package working", logger);
|
||||
var success = dotnet.New(tempDir.DirInfo.FullName);
|
||||
if (!success)
|
||||
{
|
||||
@@ -322,7 +433,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: nugetConfig));
|
||||
if (!res.Success)
|
||||
{
|
||||
if (res.HasNugetPackageSourceError && nugetConfig is not null)
|
||||
if (tryWithoutNugetConfig && res.HasNugetPackageSourceError && nugetConfig is not null)
|
||||
{
|
||||
// Restore could not be completed because the listed source is unavailable. Try without the nuget.config:
|
||||
res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: null, ForceReevaluation: true));
|
||||
@@ -385,16 +496,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsFeedReachable(string feed)
|
||||
private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount, bool allowExceptions = true)
|
||||
{
|
||||
logger.LogInfo($"Checking if Nuget feed '{feed}' is reachable...");
|
||||
using HttpClient client = new();
|
||||
int timeoutMilliSeconds = int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeout), out timeoutMilliSeconds)
|
||||
? timeoutMilliSeconds
|
||||
: 1000;
|
||||
int tryCount = int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCount), out tryCount)
|
||||
? tryCount
|
||||
: 4;
|
||||
|
||||
for (var i = 0; i < tryCount; i++)
|
||||
{
|
||||
@@ -403,6 +508,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
try
|
||||
{
|
||||
ExecuteGetRequest(feed, client, cts.Token).GetAwaiter().GetResult();
|
||||
logger.LogInfo($"Querying Nuget feed '{feed}' succeeded.");
|
||||
return true;
|
||||
}
|
||||
catch (Exception exc)
|
||||
@@ -411,14 +517,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
tce.CancellationToken == cts.Token &&
|
||||
cts.Token.IsCancellationRequested)
|
||||
{
|
||||
logger.LogWarning($"Didn't receive answer from Nuget feed '{feed}' in {timeoutMilliSeconds}ms.");
|
||||
logger.LogInfo($"Didn't receive answer from Nuget feed '{feed}' in {timeoutMilliSeconds}ms.");
|
||||
timeoutMilliSeconds *= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're only interested in timeouts.
|
||||
logger.LogWarning($"Querying Nuget feed '{feed}' failed: {exc}");
|
||||
return true;
|
||||
var start = allowExceptions ? "Considering" : "Not considering";
|
||||
logger.LogInfo($"Querying Nuget feed '{feed}' failed in a timely manner. {start} the feed for use. The reason for the failure: {exc.Message}");
|
||||
return allowExceptions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,13 +533,31 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CheckFeeds(List<FileInfo> allFiles)
|
||||
private (int initialTimeout, int tryCount) GetFeedRequestSettings(bool isFallback)
|
||||
{
|
||||
int timeoutMilliSeconds = isFallback && int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeoutForFallback), out timeoutMilliSeconds)
|
||||
? timeoutMilliSeconds
|
||||
: int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeout), out timeoutMilliSeconds)
|
||||
? timeoutMilliSeconds
|
||||
: 1000;
|
||||
logger.LogDebug($"Initial timeout for Nuget feed reachability check is {timeoutMilliSeconds}ms.");
|
||||
|
||||
int tryCount = isFallback && int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCountForFallback), out tryCount)
|
||||
? tryCount
|
||||
: int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCount), out tryCount)
|
||||
? tryCount
|
||||
: 4;
|
||||
logger.LogDebug($"Number of tries for Nuget feed reachability check is {tryCount}.");
|
||||
|
||||
return (timeoutMilliSeconds, tryCount);
|
||||
}
|
||||
|
||||
private bool CheckFeeds()
|
||||
{
|
||||
logger.LogInfo("Checking Nuget feeds...");
|
||||
var feeds = GetAllFeeds(allFiles);
|
||||
var (explicitFeeds, allFeeds) = GetAllFeeds();
|
||||
|
||||
var excludedFeeds = Environment.GetEnvironmentVariable(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck)
|
||||
?.Split(" ", StringSplitOptions.RemoveEmptyEntries)
|
||||
var excludedFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck)
|
||||
.ToHashSet() ?? [];
|
||||
|
||||
if (excludedFeeds.Count > 0)
|
||||
@@ -440,7 +565,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
logger.LogInfo($"Excluded Nuget feeds from responsiveness check: {string.Join(", ", excludedFeeds.OrderBy(f => f))}");
|
||||
}
|
||||
|
||||
var allFeedsReachable = feeds.All(feed => excludedFeeds.Contains(feed) || IsFeedReachable(feed));
|
||||
var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: false);
|
||||
|
||||
var allFeedsReachable = explicitFeeds.All(feed => excludedFeeds.Contains(feed) || IsFeedReachable(feed, initialTimeout, tryCount));
|
||||
if (!allFeedsReachable)
|
||||
{
|
||||
logger.LogWarning("Found unreachable Nuget feed in C# analysis with build-mode 'none'. This may cause missing dependencies in the analysis.");
|
||||
@@ -453,14 +580,22 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
severity: DiagnosticMessage.TspSeverity.Warning
|
||||
));
|
||||
}
|
||||
CompilationInfos.Add(("All Nuget feeds reachable", allFeedsReachable ? "1" : "0"));
|
||||
compilationInfoContainer.CompilationInfos.Add(("All Nuget feeds reachable", allFeedsReachable ? "1" : "0"));
|
||||
|
||||
|
||||
var inheritedFeeds = allFeeds.Except(explicitFeeds).ToHashSet();
|
||||
if (inheritedFeeds.Count > 0)
|
||||
{
|
||||
logger.LogInfo($"Inherited Nuget feeds (not checked for reachability): {string.Join(", ", inheritedFeeds.OrderBy(f => f))}");
|
||||
compilationInfoContainer.CompilationInfos.Add(("Inherited Nuget feed count", inheritedFeeds.Count.ToString()));
|
||||
}
|
||||
|
||||
return allFeedsReachable;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetFeeds(string nugetConfig)
|
||||
private IEnumerable<string> GetFeeds(Func<IList<string>> getNugetFeeds)
|
||||
{
|
||||
logger.LogInfo($"Getting Nuget feeds from '{nugetConfig}'...");
|
||||
var results = dotnet.GetNugetFeeds(nugetConfig);
|
||||
var results = getNugetFeeds();
|
||||
var regex = EnabledNugetFeed();
|
||||
foreach (var result in results)
|
||||
{
|
||||
@@ -479,27 +614,51 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return url;
|
||||
if (!string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
yield return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<string> GetAllFeeds(List<FileInfo> allFiles)
|
||||
private (HashSet<string> explicitFeeds, HashSet<string> allFeeds) GetAllFeeds()
|
||||
{
|
||||
var nugetConfigs = GetAllNugetConfigs(allFiles);
|
||||
var feeds = nugetConfigs
|
||||
.SelectMany(GetFeeds)
|
||||
.Where(str => !string.IsNullOrWhiteSpace(str))
|
||||
var nugetConfigs = fileProvider.NugetConfigs;
|
||||
var explicitFeeds = nugetConfigs
|
||||
.SelectMany(config => GetFeeds(() => dotnet.GetNugetFeeds(config)))
|
||||
.ToHashSet();
|
||||
|
||||
if (feeds.Count > 0)
|
||||
if (explicitFeeds.Count > 0)
|
||||
{
|
||||
logger.LogInfo($"Found {feeds.Count} Nuget feeds in nuget.config files: {string.Join(", ", feeds.OrderBy(f => f))}");
|
||||
logger.LogInfo($"Found {explicitFeeds.Count} Nuget feeds in nuget.config files: {string.Join(", ", explicitFeeds.OrderBy(f => f))}");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("No Nuget feeds found in nuget.config files.");
|
||||
}
|
||||
return feeds;
|
||||
|
||||
// todo: this could be improved.
|
||||
// We don't have to get the feeds from each of the folders from below, it would be enought to check the folders that recursively contain the others.
|
||||
var allFeeds = nugetConfigs
|
||||
.Select(config =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return new FileInfo(config).Directory?.FullName;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger.LogWarning($"Failed to get directory of '{config}': {exc}");
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.Where(folder => folder != null)
|
||||
.SelectMany(folder => GetFeeds(() => dotnet.GetNugetFeedsFromFolder(folder!)))
|
||||
.ToHashSet();
|
||||
|
||||
logger.LogInfo($"Found {allFeeds.Count} Nuget feeds (with inherited ones) in nuget.config files: {string.Join(", ", allFeeds.OrderBy(f => f))}");
|
||||
|
||||
return (explicitFeeds, allFeeds);
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"<TargetFramework>.*</TargetFramework>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
|
||||
@@ -510,5 +669,28 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
[GeneratedRegex(@"^E\s(.*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
|
||||
private static partial Regex EnabledNugetFeed();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PackageDirectory?.Dispose();
|
||||
legacyPackageDirectory?.Dispose();
|
||||
missingPackageDirectory?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a unique temp directory for the packages associated
|
||||
/// with this source tree. Use a SHA1 of the directory name.
|
||||
/// </summary>
|
||||
/// <returns>The full path of the temp directory.</returns>
|
||||
private static string ComputeTempDirectoryPath(string srcDir, string subfolderName)
|
||||
{
|
||||
var bytes = Encoding.Unicode.GetBytes(srcDir);
|
||||
var sha = SHA1.HashData(bytes);
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in sha.Take(8))
|
||||
sb.AppendFormat("{0:x2}", b);
|
||||
|
||||
return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out var _), sb.ToString(), subfolderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
public interface ISourceGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the paths to the generated source files.
|
||||
/// </summary>
|
||||
IEnumerable<string> Generate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal class ImplicitUsingsGenerator : SourceGeneratorBase
|
||||
{
|
||||
private readonly FileContent fileContent;
|
||||
|
||||
public ImplicitUsingsGenerator(FileContent fileContent, ILogger logger, TemporaryDirectory tempWorkingDirectory)
|
||||
: base(logger, tempWorkingDirectory)
|
||||
{
|
||||
this.fileContent = fileContent;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Generate()
|
||||
{
|
||||
var usings = new HashSet<string>();
|
||||
if (!fileContent.UseImplicitUsings)
|
||||
{
|
||||
logger.LogDebug("Skipping implicit usings generation");
|
||||
return [];
|
||||
}
|
||||
|
||||
// Hardcoded values from https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives
|
||||
usings.UnionWith([ "System", "System.Collections.Generic", "System.IO", "System.Linq", "System.Net.Http", "System.Threading",
|
||||
"System.Threading.Tasks" ]);
|
||||
|
||||
if (fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
usings.UnionWith([ "System.Net.Http.Json", "Microsoft.AspNetCore.Builder", "Microsoft.AspNetCore.Hosting",
|
||||
"Microsoft.AspNetCore.Http", "Microsoft.AspNetCore.Routing", "Microsoft.Extensions.Configuration",
|
||||
"Microsoft.Extensions.DependencyInjection", "Microsoft.Extensions.Hosting", "Microsoft.Extensions.Logging" ]);
|
||||
}
|
||||
|
||||
if (fileContent.UseWindowsForms)
|
||||
{
|
||||
usings.UnionWith(["System.Drawing", "System.Windows.Forms"]);
|
||||
}
|
||||
|
||||
usings.UnionWith(fileContent.CustomImplicitUsings);
|
||||
|
||||
logger.LogInfo($"Generating source file for implicit usings. Namespaces: {string.Join(", ", usings.OrderBy(u => u))}");
|
||||
|
||||
if (usings.Count > 0)
|
||||
{
|
||||
var tempDir = GetTemporaryWorkingDirectory("implicitUsings");
|
||||
var path = Path.Combine(tempDir, "GlobalUsings.g.cs");
|
||||
using (var writer = new StreamWriter(path))
|
||||
{
|
||||
writer.WriteLine("// <auto-generated/>");
|
||||
writer.WriteLine("");
|
||||
|
||||
foreach (var u in usings.OrderBy(u => u))
|
||||
{
|
||||
writer.WriteLine($"global using global::{u};");
|
||||
}
|
||||
}
|
||||
|
||||
return [path];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,9 +64,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
try
|
||||
{
|
||||
logger.LogInfo("Produce analyzer config content.");
|
||||
GenerateAnalyzerConfig(cshtmls, analyzerConfig);
|
||||
|
||||
logger.LogInfo($"Analyzer config content: {File.ReadAllText(analyzerConfig)}");
|
||||
logger.LogDebug($"Analyzer config content: {File.ReadAllText(analyzerConfig)}");
|
||||
|
||||
var args = new StringBuilder();
|
||||
args.Append($"/target:exe /generatedfilesout:\"{outputFolder}\" /out:\"{dllPath}\" /analyzerconfig:\"{analyzerConfig}\" ");
|
||||
@@ -88,7 +89,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
var argsString = args.ToString();
|
||||
|
||||
logger.LogInfo($"Running CSC to generate Razor source files with arguments: {argsString}.");
|
||||
logger.LogInfo($"Running CSC to generate Razor source files.");
|
||||
logger.LogDebug($"Running CSC to generate Razor source files with arguments: {argsString}.");
|
||||
|
||||
using (var sw = new StreamWriter(cscArgsPath))
|
||||
{
|
||||
@@ -126,4 +128,4 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal abstract class SourceGeneratorBase : ISourceGenerator
|
||||
{
|
||||
protected readonly ILogger logger;
|
||||
protected readonly TemporaryDirectory tempWorkingDirectory;
|
||||
|
||||
public SourceGeneratorBase(ILogger logger, TemporaryDirectory tempWorkingDirectory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.tempWorkingDirectory = tempWorkingDirectory;
|
||||
}
|
||||
|
||||
public abstract IEnumerable<string> Generate();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary directory with the given subfolder name.
|
||||
/// The created directory might be inside the repo folder, and it is deleted when the temporary working directory is disposed.
|
||||
/// </summary>
|
||||
protected string GetTemporaryWorkingDirectory(string subfolder)
|
||||
{
|
||||
var temp = Path.Combine(tempWorkingDirectory.ToString(), subfolder);
|
||||
Directory.CreateDirectory(temp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal class WebViewGenerator : SourceGeneratorBase
|
||||
{
|
||||
private readonly FileProvider fileProvider;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly IDotNet dotnet;
|
||||
private readonly ICompilationInfoContainer compilationInfoContainer;
|
||||
private readonly IEnumerable<string> references;
|
||||
|
||||
public WebViewGenerator(
|
||||
FileProvider fileProvider,
|
||||
FileContent fileContent,
|
||||
IDotNet dotnet,
|
||||
ICompilationInfoContainer compilationInfoContainer,
|
||||
ILogger logger,
|
||||
TemporaryDirectory tempWorkingDirectory,
|
||||
IEnumerable<string> references) : base(logger, tempWorkingDirectory)
|
||||
{
|
||||
this.fileProvider = fileProvider;
|
||||
this.fileContent = fileContent;
|
||||
this.dotnet = dotnet;
|
||||
this.compilationInfoContainer = compilationInfoContainer;
|
||||
this.references = references;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Generate()
|
||||
{
|
||||
var webViewExtractionOption = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WebViewGeneration);
|
||||
if (webViewExtractionOption == null ||
|
||||
bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
|
||||
shouldExtractWebViews)
|
||||
{
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "1"));
|
||||
return GenerateSourceFilesFromWebViews();
|
||||
}
|
||||
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "0"));
|
||||
return [];
|
||||
}
|
||||
|
||||
private IEnumerable<string> GenerateSourceFilesFromWebViews()
|
||||
{
|
||||
var views = fileProvider.RazorViews;
|
||||
if (views.Count == 0)
|
||||
{
|
||||
logger.LogDebug("No cshtml or razor files found.");
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.LogInfo($"Found {views.Count} cshtml and razor files.");
|
||||
|
||||
if (!fileContent.IsAspNetCoreDetected)
|
||||
{
|
||||
logger.LogInfo("Generating source files from cshtml files is only supported for new (SDK-style) project files");
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.LogInfo("Generating source files from cshtml and razor files...");
|
||||
|
||||
var sdk = new Sdk(dotnet).GetNewestSdk();
|
||||
if (sdk != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var razor = new Razor(sdk, dotnet, logger);
|
||||
var targetDir = GetTemporaryWorkingDirectory("razor");
|
||||
var generatedFiles = razor.GenerateFiles(views, references, targetDir);
|
||||
return generatedFiles ?? [];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// It's okay, we tried our best to generate source files from cshtml files.
|
||||
logger.LogInfo($"Failed to generate source files from cshtml files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,12 +111,12 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
AnalysisAction.UpToDate => "up to date",
|
||||
_ => "unknown action"
|
||||
};
|
||||
logger.LogInfo($"[{item}/{total}] {source} ({extra})");
|
||||
logger.LogDebug($"[{item}/{total}] {source} ({extra})");
|
||||
}
|
||||
|
||||
public void Started(int item, int total, string source)
|
||||
{
|
||||
logger.LogInfo($"[{item}/{total}] {source} (processing started)");
|
||||
logger.LogDebug($"[{item}/{total}] {source} (processing started)");
|
||||
}
|
||||
|
||||
public void MissingType(string type)
|
||||
@@ -166,4 +166,4 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
return ExitCode.Ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// </summary>
|
||||
public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k)
|
||||
{
|
||||
if (k == ExprKind.ADDRESS_OF)
|
||||
if (k == ExprKind.ADDRESS_OF || k == ExprKind.SUPPRESS_NULLABLE_WARNING)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -314,24 +314,46 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given b in a?.b.c, return a.
|
||||
/// Given `b` in `a?.b.c`, return `(a?.b, a?.b)`.
|
||||
///
|
||||
/// Given `c` in `a?.b?.c.d`, return `(b?.c, a?.b?.c)`.
|
||||
/// </summary>
|
||||
/// <param name="node">A MemberBindingExpression.</param>
|
||||
/// <returns>The qualifier of the conditional access.</returns>
|
||||
protected static ExpressionSyntax FindConditionalQualifier(ExpressionSyntax node)
|
||||
/// <returns>The conditional access.</returns>
|
||||
public static (ConditionalAccessExpressionSyntax Parent, ConditionalAccessExpressionSyntax Root) FindConditionalAccessParent(ExpressionSyntax node)
|
||||
{
|
||||
for (SyntaxNode? n = node; n is not null; n = n.Parent)
|
||||
(ConditionalAccessExpressionSyntax, ConditionalAccessExpressionSyntax)? res = null;
|
||||
SyntaxNode? prev = null;
|
||||
|
||||
for (SyntaxNode? n = node; n is not null; prev = n, n = n.Parent)
|
||||
{
|
||||
if (n.Parent is ConditionalAccessExpressionSyntax conditionalAccess &&
|
||||
conditionalAccess.WhenNotNull == n)
|
||||
if (n is ConditionalAccessExpressionSyntax conditionalAccess &&
|
||||
(prev is null || conditionalAccess.WhenNotNull == prev))
|
||||
{
|
||||
return conditionalAccess.Expression;
|
||||
res = res is null ? (conditionalAccess, conditionalAccess) : (res.Value.Item1, conditionalAccess);
|
||||
}
|
||||
else if (res.HasValue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res.HasValue)
|
||||
{
|
||||
return res.Value;
|
||||
}
|
||||
|
||||
throw new InternalError(node, "Unable to locate a ConditionalAccessExpression");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given b in a?.b.c, return a.
|
||||
/// </summary>
|
||||
/// <param name="node">A MemberBindingExpression.</param>
|
||||
/// <returns>The qualifier of the conditional access.</returns>
|
||||
protected static ExpressionSyntax FindConditionalQualifier(ExpressionSyntax node) =>
|
||||
FindConditionalAccessParent(node).Parent.Expression;
|
||||
|
||||
public void MakeConditional(TextWriter trapFile)
|
||||
{
|
||||
trapFile.conditional_access(this);
|
||||
|
||||
@@ -125,11 +125,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
cachedLocation = Context.CreateLocation(CodeAnalysisLocation);
|
||||
return cachedLocation;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
cachedLocation = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ExprKind Kind { get; set; } = ExprKind.UNKNOWN;
|
||||
|
||||
@@ -79,7 +79,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
internal class BindingElementAccess : ElementAccess
|
||||
{
|
||||
private BindingElementAccess(ExpressionNodeInfo info)
|
||||
: base(info, FindConditionalQualifier(info.Node), ((ElementBindingExpressionSyntax)info.Node).ArgumentList) { }
|
||||
: base(info, FindConditionalQualifier(info.Node), ((ElementBindingExpressionSyntax)info.Node).ArgumentList)
|
||||
{
|
||||
}
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new BindingElementAccess(info).TryPopulate();
|
||||
|
||||
|
||||
@@ -21,11 +21,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
Create(Context, operand, this, 0);
|
||||
OperatorCall(trapFile, Syntax);
|
||||
|
||||
if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) &&
|
||||
Kind == ExprKind.OPERATOR_INVOCATION)
|
||||
{
|
||||
OperatorCall(trapFile, Syntax);
|
||||
trapFile.mutator_invocation_mode(this, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
/// <param name="l1">The location to extend.</param>
|
||||
/// <param name="n2">The node to extend the location to.</param>
|
||||
/// <returns>Extended location.</returns>
|
||||
public static Location ExtendLocation(this Location l1, SyntaxNode n2)
|
||||
public static Location ExtendLocation(this Location l1, SyntaxNode n2, bool onlyStart = false)
|
||||
{
|
||||
if (n2 is null)
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
|
||||
var l2 = n2.FixedLocation();
|
||||
var start = System.Math.Min(l1.SourceSpan.Start, l2.SourceSpan.Start);
|
||||
var end = System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End);
|
||||
var end = onlyStart ? l1.SourceSpan.End : System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End);
|
||||
return Location.Create(n2.SyntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start));
|
||||
}
|
||||
|
||||
@@ -85,6 +85,17 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
return ((CatchDeclarationSyntax)node).Identifier.GetLocation();
|
||||
case SyntaxKind.LabeledStatement:
|
||||
return ((LabeledStatementSyntax)node).Identifier.GetLocation();
|
||||
case SyntaxKind.ElementBindingExpression:
|
||||
return node.GetLocation().ExtendLocation(Entities.Expression.FindConditionalAccessParent((ElementBindingExpressionSyntax)node).Root, onlyStart: true);
|
||||
case SyntaxKind.MemberBindingExpression:
|
||||
return node.GetLocation().ExtendLocation(Entities.Expression.FindConditionalAccessParent((MemberBindingExpressionSyntax)node).Root, onlyStart: true);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return node.GetLocation().ExtendLocation(((ElementAccessExpressionSyntax)node).Expression);
|
||||
case SyntaxKind.SimpleMemberAccessExpression:
|
||||
return node.GetLocation().ExtendLocation(((MemberAccessExpressionSyntax)node).Expression);
|
||||
case SyntaxKind.InvocationExpression:
|
||||
return node.GetLocation().ExtendLocation(((InvocationExpressionSyntax)node).Expression);
|
||||
|
||||
default:
|
||||
result = node.GetLocation();
|
||||
break;
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Semmle.Extraction.Tests
|
||||
{
|
||||
private readonly IList<string> output;
|
||||
private string lastArgs = "";
|
||||
public string WorkingDirectory { get; private set; } = "";
|
||||
public bool Success { get; set; } = true;
|
||||
|
||||
public DotNetCliInvokerStub(IList<string> output)
|
||||
@@ -19,19 +20,25 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
public string Exec => "dotnet";
|
||||
|
||||
public bool RunCommand(string args)
|
||||
public bool RunCommand(string args, bool silent)
|
||||
{
|
||||
lastArgs = args;
|
||||
return Success;
|
||||
}
|
||||
|
||||
public bool RunCommand(string args, out IList<string> output)
|
||||
public bool RunCommand(string args, out IList<string> output, bool silent)
|
||||
{
|
||||
lastArgs = args;
|
||||
output = this.output;
|
||||
return Success;
|
||||
}
|
||||
|
||||
public bool RunCommand(string args, string? workingDirectory, out IList<string> output, bool silent)
|
||||
{
|
||||
WorkingDirectory = workingDirectory ?? "";
|
||||
return RunCommand(args, out output, silent);
|
||||
}
|
||||
|
||||
public string GetLastArgs() => lastArgs;
|
||||
}
|
||||
|
||||
@@ -262,5 +269,36 @@ namespace Semmle.Extraction.Tests
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
Assert.Equal("exec myarg1 myarg2", lastArgs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestNugetFeeds()
|
||||
{
|
||||
// Setup
|
||||
var dotnetCliInvoker = new DotNetCliInvokerStub(new List<string>());
|
||||
var dotnet = MakeDotnet(dotnetCliInvoker);
|
||||
|
||||
// Execute
|
||||
dotnet.GetNugetFeeds("abc");
|
||||
|
||||
// Verify
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
Assert.Equal("nuget list source --format Short --configfile \"abc\"", lastArgs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestNugetFeedsFromFolder()
|
||||
{
|
||||
// Setup
|
||||
var dotnetCliInvoker = new DotNetCliInvokerStub(new List<string>());
|
||||
var dotnet = MakeDotnet(dotnetCliInvoker);
|
||||
|
||||
// Execute
|
||||
dotnet.GetNugetFeedsFromFolder("abc");
|
||||
|
||||
// Verify
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
Assert.Equal("nuget list source --format Short", lastArgs);
|
||||
Assert.Equal("abc", dotnetCliInvoker.WorkingDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Semmle.Extraction.Tests
|
||||
public bool Exec(string execArgs) => true;
|
||||
|
||||
public IList<string> GetNugetFeeds(string nugetConfig) => [];
|
||||
|
||||
public IList<string> GetNugetFeedsFromFolder(string folderPath) => [];
|
||||
}
|
||||
|
||||
public class RuntimeTests
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
|
||||
@@ -34,5 +35,10 @@ namespace Semmle.Util
|
||||
var _ = bool.TryParse(env, out var value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetURLs(string name)
|
||||
{
|
||||
return Environment.GetEnvironmentVariable(name)?.Split(" ", StringSplitOptions.RemoveEmptyEntries) ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Util
|
||||
{
|
||||
@@ -9,17 +10,29 @@ namespace Semmle.Util
|
||||
/// </summary>
|
||||
public sealed class TemporaryDirectory : IDisposable
|
||||
{
|
||||
private readonly string userReportedDirectoryPurpose;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public DirectoryInfo DirInfo { get; }
|
||||
|
||||
public TemporaryDirectory(string name)
|
||||
public TemporaryDirectory(string name, string userReportedDirectoryPurpose, ILogger logger)
|
||||
{
|
||||
DirInfo = new DirectoryInfo(name);
|
||||
DirInfo.Create();
|
||||
this.userReportedDirectoryPurpose = userReportedDirectoryPurpose;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DirInfo.Delete(true);
|
||||
try
|
||||
{
|
||||
DirInfo.Delete(true);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger.LogInfo($"Couldn't delete {userReportedDirectoryPurpose} directory {exc.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => DirInfo.FullName.ToString();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user