Merge branch 'main' into enable-sound-ir

This commit is contained in:
Mathias Vorreiter Pedersen
2024-04-16 10:46:59 +01:00
549 changed files with 17277 additions and 10822 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
failures
testFailures
failures

View File

@@ -1,2 +1,2 @@
failures
testFailures
failures

View File

@@ -1,2 +1,2 @@
failures
testFailures
failures

View File

@@ -1,2 +1,2 @@
failures
testFailures
failures

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
failures
testFailures
failures

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,6 +50,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
public bool IsAspNetCoreDetected
{
get
{
return IsNewProjectStructureUsed && UseAspNetCoreDlls;
}
}
private bool useImplicitUsings = false;
public bool UseImplicitUsings

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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