mirror of
https://github.com/github/codeql.git
synced 2026-05-05 05:35:13 +02:00
Merge branch 'main' into redsun82/gen-file-docs
This commit is contained in:
@@ -31,6 +31,11 @@ abstract class MustFlowConfiguration extends string {
|
||||
*/
|
||||
abstract predicate isSink(Operand sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `instr` is prohibited.
|
||||
*/
|
||||
predicate isBarrier(Instruction instr) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -48,18 +53,21 @@ abstract class MustFlowConfiguration extends string {
|
||||
*/
|
||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||
this.isSource(source.getInstruction()) and
|
||||
source.getASuccessor+() = sink
|
||||
source.getASuccessor*() = sink
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||
config.isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node, config) and
|
||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||
not config.isBarrier(node) and
|
||||
(
|
||||
config.isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node, config) and
|
||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ private class Getaddrinfo extends TaintFunction, ArrayFunction, RemoteFlowSource
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
|
||||
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(3) and
|
||||
output.isParameterDeref(3, 2) and
|
||||
description = "address returned by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
||||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||
|
||||
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
||||
input.isParameterDeref(1) and description = "buffer sent by " + this.getName()
|
||||
input.isParameterDeref(1, 1) and description = "buffer sent by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||
|
||||
@@ -8,7 +8,7 @@ import semmle.code.cpp.Parameter
|
||||
|
||||
private newtype TFunctionInput =
|
||||
TInParameter(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||
TInQualifierObject() or
|
||||
TInQualifierAddress() or
|
||||
TInReturnValueDeref()
|
||||
@@ -245,15 +245,18 @@ class InParameter extends FunctionInput, TInParameter {
|
||||
*/
|
||||
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
||||
ParameterIndex index;
|
||||
int indirectionIndex;
|
||||
|
||||
InParameterDeref() { this = TInParameterDeref(index) }
|
||||
InParameterDeref() { this = TInParameterDeref(index, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "InParameterDeref " + index.toString() }
|
||||
|
||||
/** Gets the zero-based index of the parameter. */
|
||||
ParameterIndex getIndex() { result = index }
|
||||
|
||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
||||
override predicate isParameterDeref(ParameterIndex i, int indirection) {
|
||||
i = index and indirectionIndex = indirection
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,10 +324,10 @@ class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
|
||||
}
|
||||
|
||||
private newtype TFunctionOutput =
|
||||
TOutParameterDeref(ParameterIndex i) or
|
||||
TOutParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||
TOutQualifierObject() or
|
||||
TOutReturnValue() or
|
||||
TOutReturnValueDeref()
|
||||
TOutReturnValueDeref(int indirections) { indirections = [1, 2] }
|
||||
|
||||
/**
|
||||
* An output from a function. This can be:
|
||||
@@ -498,17 +501,16 @@ class FunctionOutput extends TFunctionOutput {
|
||||
*/
|
||||
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
||||
ParameterIndex index;
|
||||
int indirectionIndex;
|
||||
|
||||
OutParameterDeref() { this = TOutParameterDeref(index) }
|
||||
OutParameterDeref() { this = TOutParameterDeref(index, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "OutParameterDeref " + index.toString() }
|
||||
|
||||
ParameterIndex getIndex() { result = index }
|
||||
|
||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
||||
|
||||
override predicate isParameterDeref(ParameterIndex i, int ind) {
|
||||
this.isParameterDeref(i) and ind = 1
|
||||
i = index and ind = indirectionIndex
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,4 +574,8 @@ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
|
||||
override string toString() { result = "OutReturnValueDeref" }
|
||||
|
||||
override predicate isReturnValueDeref() { any() }
|
||||
|
||||
override predicate isReturnValueDeref(int indirectionIndex) {
|
||||
this = TOutReturnValueDeref(indirectionIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
* `upper` is true, and can be traced back to a guard represented by `reason`.
|
||||
*/
|
||||
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getUnconvertedResultExpression() = e
|
||||
|
|
||||
exists(SemanticExprConfig::Expr semExpr | semExpr.getUnconvertedResultExpression() = e |
|
||||
semBounded(semExpr, b, delta, upper, reason)
|
||||
)
|
||||
}
|
||||
@@ -30,9 +28,7 @@ predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||
* The `Expr` may be a conversion.
|
||||
*/
|
||||
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getConverted().getConvertedResultExpression() = e
|
||||
|
|
||||
exists(SemanticExprConfig::Expr semExpr | semExpr.getConvertedResultExpression() = e |
|
||||
semBounded(semExpr, b, delta, upper, reason)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ predicate exprMightOverflowNegatively(Expr expr) {
|
||||
lowerBound(expr) < exprMinVal(expr)
|
||||
or
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getAst() = expr and
|
||||
semExpr.getAst() = expr and
|
||||
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
||||
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
||||
)
|
||||
@@ -126,7 +126,7 @@ predicate exprMightOverflowPositively(Expr expr) {
|
||||
upperBound(expr) > exprMaxVal(expr)
|
||||
or
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getAst() = expr and
|
||||
semExpr.getAst() = expr and
|
||||
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
||||
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
||||
)
|
||||
|
||||
@@ -12,9 +12,6 @@ class SemBasicBlock extends Specific::BasicBlock {
|
||||
/** Holds if this block (transitively) dominates `otherblock`. */
|
||||
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
||||
|
||||
/** Holds if this block has dominance information. */
|
||||
final predicate hasDominanceInformation() { Specific::hasDominanceInformation(this) }
|
||||
|
||||
/** Gets an expression that is evaluated in this basic block. */
|
||||
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
private import Semantic
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
private import SemanticType
|
||||
|
||||
/**
|
||||
* An language-neutral expression.
|
||||
@@ -241,8 +242,21 @@ class SemConvertExpr extends SemUnaryExpr {
|
||||
SemConvertExpr() { opcode instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
private import semmle.code.cpp.ir.IR as IR
|
||||
|
||||
/** A conversion instruction which is guaranteed to not overflow. */
|
||||
private class SafeConversion extends IR::ConvertInstruction {
|
||||
SafeConversion() {
|
||||
exists(SemType tFrom, SemType tTo |
|
||||
tFrom = getSemanticType(super.getUnary().getResultIRType()) and
|
||||
tTo = getSemanticType(super.getResultIRType()) and
|
||||
conversionCannotOverflow(tFrom, tTo)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SemCopyValueExpr extends SemUnaryExpr {
|
||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue }
|
||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue or this instanceof SafeConversion }
|
||||
}
|
||||
|
||||
class SemNegateExpr extends SemUnaryExpr {
|
||||
|
||||
@@ -12,87 +12,10 @@ private import semmle.code.cpp.ir.ValueNumbering
|
||||
module SemanticExprConfig {
|
||||
class Location = Cpp::Location;
|
||||
|
||||
/** A `ConvertInstruction` or a `CopyValueInstruction`. */
|
||||
private class Conversion extends IR::UnaryInstruction {
|
||||
Conversion() {
|
||||
this instanceof IR::CopyValueInstruction
|
||||
or
|
||||
this instanceof IR::ConvertInstruction
|
||||
}
|
||||
|
||||
/** Holds if this instruction converts a value of type `tFrom` to a value of type `tTo`. */
|
||||
predicate converts(SemType tFrom, SemType tTo) {
|
||||
tFrom = getSemanticType(this.getUnary().getResultIRType()) and
|
||||
tTo = getSemanticType(this.getResultIRType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a conversion-like instruction that consumes `op`, and
|
||||
* which is guaranteed to not overflow.
|
||||
*/
|
||||
private IR::Instruction safeConversion(IR::Operand op) {
|
||||
exists(Conversion conv, SemType tFrom, SemType tTo |
|
||||
conv.converts(tFrom, tTo) and
|
||||
conversionCannotOverflow(tFrom, tTo) and
|
||||
conv.getUnaryOperand() = op and
|
||||
result = conv
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `i1 = i2` or if `i2` is a safe conversion that consumes `i1`. */
|
||||
private predicate idOrSafeConversion(IR::Instruction i1, IR::Instruction i2) {
|
||||
not i1.getResultIRType() instanceof IR::IRVoidType and
|
||||
(
|
||||
i1 = i2
|
||||
or
|
||||
i2 = safeConversion(i1.getAUse()) and
|
||||
i1.getBlock() = i2.getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
module Equiv = QlBuiltins::EquivalenceRelation<IR::Instruction, idOrSafeConversion/2>;
|
||||
|
||||
/**
|
||||
* The expressions on which we perform range analysis.
|
||||
*/
|
||||
class Expr extends Equiv::EquivalenceClass {
|
||||
/** Gets the n'th instruction in this equivalence class. */
|
||||
private IR::Instruction getInstruction(int n) {
|
||||
result =
|
||||
rank[n + 1](IR::Instruction instr, int i, IR::IRBlock block |
|
||||
this = Equiv::getEquivalenceClass(instr) and block.getInstruction(i) = instr
|
||||
|
|
||||
instr order by i
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getUnconverted().toString() }
|
||||
|
||||
/** Gets the basic block of this expression. */
|
||||
IR::IRBlock getBlock() { result = this.getUnconverted().getBlock() }
|
||||
|
||||
/** Gets the unconverted instruction associated with this expression. */
|
||||
IR::Instruction getUnconverted() { result = this.getInstruction(0) }
|
||||
|
||||
/**
|
||||
* Gets the final instruction associated with this expression. This
|
||||
* represents the result after applying all the safe conversions.
|
||||
*/
|
||||
IR::Instruction getConverted() {
|
||||
exists(int n |
|
||||
result = this.getInstruction(n) and
|
||||
not exists(this.getInstruction(n + 1))
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the type of the result produced by this instruction. */
|
||||
IR::IRType getResultIRType() { result = this.getConverted().getResultIRType() }
|
||||
|
||||
/** Gets the location of the source code for this expression. */
|
||||
Location getLocation() { result = this.getUnconverted().getLocation() }
|
||||
}
|
||||
class Expr = IR::Instruction;
|
||||
|
||||
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
||||
|
||||
@@ -139,12 +62,12 @@ module SemanticExprConfig {
|
||||
|
||||
predicate stringLiteral(Expr expr, SemType type, string value) {
|
||||
anyConstantExpr(expr, type, value) and
|
||||
expr.getUnconverted() instanceof IR::StringConstantInstruction
|
||||
expr instanceof IR::StringConstantInstruction
|
||||
}
|
||||
|
||||
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
||||
exists(IR::BinaryInstruction instr |
|
||||
instr = expr.getUnconverted() and
|
||||
instr = expr and
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
leftOperand = getSemanticExpr(instr.getLeft()) and
|
||||
rightOperand = getSemanticExpr(instr.getRight()) and
|
||||
@@ -154,14 +77,14 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
||||
exists(IR::UnaryInstruction instr | instr = expr.getUnconverted() |
|
||||
exists(IR::UnaryInstruction instr | instr = expr |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
operand = getSemanticExpr(instr.getUnary()) and
|
||||
// REVIEW: Merge the two operand types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
or
|
||||
exists(IR::StoreInstruction instr | instr = expr.getUnconverted() |
|
||||
exists(IR::StoreInstruction instr | instr = expr |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
operand = getSemanticExpr(instr.getSourceValue()) and
|
||||
opcode instanceof Opcode::Store
|
||||
@@ -170,13 +93,13 @@ module SemanticExprConfig {
|
||||
|
||||
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
||||
exists(IR::LoadInstruction load |
|
||||
load = expr.getUnconverted() and
|
||||
load = expr and
|
||||
type = getSemanticType(load.getResultIRType()) and
|
||||
opcode instanceof Opcode::Load
|
||||
)
|
||||
or
|
||||
exists(IR::InitializeParameterInstruction init |
|
||||
init = expr.getUnconverted() and
|
||||
init = expr and
|
||||
type = getSemanticType(init.getResultIRType()) and
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
)
|
||||
@@ -199,8 +122,6 @@ module SemanticExprConfig {
|
||||
dominator.dominates(dominated)
|
||||
}
|
||||
|
||||
predicate hasDominanceInformation(BasicBlock block) { any() }
|
||||
|
||||
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
|
||||
|
||||
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
@@ -209,17 +130,7 @@ module SemanticExprConfig {
|
||||
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
||||
TSsaPointerArithmeticGuard(ValueNumber instr) {
|
||||
exists(Guard g, IR::Operand use |
|
||||
use = instr.getAUse() and use.getIRType() instanceof IR::IRAddressType
|
||||
|
|
||||
g.comparesLt(use, _, _, _, _) or
|
||||
g.comparesLt(_, use, _, _, _) or
|
||||
g.comparesEq(use, _, _, _, _) or
|
||||
g.comparesEq(_, use, _, _, _)
|
||||
)
|
||||
}
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||
|
||||
class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
@@ -228,8 +139,6 @@ module SemanticExprConfig {
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
ValueNumber asPointerArithGuard() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
}
|
||||
|
||||
@@ -245,18 +154,6 @@ module SemanticExprConfig {
|
||||
final override IR::Instruction asInstruction() { result = instr }
|
||||
}
|
||||
|
||||
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
|
||||
ValueNumber vn;
|
||||
|
||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(vn) }
|
||||
|
||||
final override string toString() { result = vn.toString() }
|
||||
|
||||
final override Location getLocation() { result = vn.getLocation() }
|
||||
|
||||
final override ValueNumber asPointerArithGuard() { result = vn }
|
||||
}
|
||||
|
||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||
IR::Operand op;
|
||||
|
||||
@@ -289,11 +186,7 @@ module SemanticExprConfig {
|
||||
)
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) {
|
||||
result.getUnconverted().(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
||||
or
|
||||
result.getUnconverted() = v.asPointerArithGuard().getAnInstruction()
|
||||
}
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||
@@ -305,81 +198,15 @@ module SemanticExprConfig {
|
||||
result = v.asOperand().getUse().getBlock()
|
||||
}
|
||||
|
||||
private newtype TReadPosition =
|
||||
TReadPositionBlock(IR::IRBlock block) or
|
||||
TReadPositionPhiInputEdge(IR::IRBlock pred, IR::IRBlock succ) {
|
||||
exists(IR::PhiInputOperand input |
|
||||
pred = input.getPredecessorBlock() and
|
||||
succ = input.getUse().getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
class SsaReadPosition extends TReadPosition {
|
||||
string toString() { none() }
|
||||
|
||||
Location getLocation() { none() }
|
||||
|
||||
predicate hasRead(SsaVariable v) { none() }
|
||||
}
|
||||
|
||||
private class SsaReadPositionBlock extends SsaReadPosition, TReadPositionBlock {
|
||||
IR::IRBlock block;
|
||||
|
||||
SsaReadPositionBlock() { this = TReadPositionBlock(block) }
|
||||
|
||||
final override string toString() { result = block.toString() }
|
||||
|
||||
final override Location getLocation() { result = block.getLocation() }
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
||||
|
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SsaReadPositionPhiInputEdge extends SsaReadPosition, TReadPositionPhiInputEdge {
|
||||
IR::IRBlock pred;
|
||||
IR::IRBlock succ;
|
||||
|
||||
SsaReadPositionPhiInputEdge() { this = TReadPositionPhiInputEdge(pred, succ) }
|
||||
|
||||
final override string toString() { result = pred.toString() + "->" + succ.toString() }
|
||||
|
||||
final override Location getLocation() { result = succ.getLocation() }
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
||||
|
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate hasReadOfSsaVariable(SsaReadPosition pos, SsaVariable v) { pos.hasRead(v) }
|
||||
|
||||
predicate readBlock(SsaReadPosition pos, BasicBlock block) { pos = TReadPositionBlock(block) }
|
||||
|
||||
predicate phiInputEdge(SsaReadPosition pos, BasicBlock origBlock, BasicBlock phiBlock) {
|
||||
pos = TReadPositionPhiInputEdge(origBlock, phiBlock)
|
||||
}
|
||||
|
||||
predicate phiInput(SsaReadPosition pos, SsaVariable phi, SsaVariable input) {
|
||||
/** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */
|
||||
predicate phiInputFromBlock(SsaVariable phi, SsaVariable inp, BasicBlock bb) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
||||
|
|
||||
bb = operand.getPredecessorBlock() and
|
||||
phi.asInstruction() = operand.getUse() and
|
||||
(
|
||||
input.asInstruction() = operand.getDef()
|
||||
inp.asInstruction() = operand.getDef()
|
||||
or
|
||||
input.asOperand() = operand
|
||||
inp.asOperand() = operand
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -433,7 +260,7 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
/** Gets the expression associated with `instr`. */
|
||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) }
|
||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = instr }
|
||||
}
|
||||
|
||||
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
||||
|
||||
@@ -35,32 +35,4 @@ predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean b2) {
|
||||
Specific::implies_v2(g1, b1, g2, b2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` directly controls the position `controlled` with the
|
||||
* value `testIsTrue`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate semGuardDirectlyControlsSsaRead(
|
||||
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
|
||||
) {
|
||||
guard.directlyControls(controlled.(SemSsaReadPositionBlock).getBlock(), testIsTrue)
|
||||
or
|
||||
exists(SemSsaReadPositionPhiInputEdge controlledEdge | controlledEdge = controlled |
|
||||
guard.directlyControls(controlledEdge.getOrigBlock(), testIsTrue) or
|
||||
guard.hasBranchEdge(controlledEdge.getOrigBlock(), controlledEdge.getPhiBlock(), testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` controls the position `controlled` with the value `testIsTrue`.
|
||||
*/
|
||||
predicate semGuardControlsSsaRead(SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue) {
|
||||
semGuardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
|
||||
or
|
||||
exists(SemGuard guard0, boolean testIsTrue0 |
|
||||
semImplies_v2(guard0, testIsTrue0, guard, testIsTrue) and
|
||||
semGuardControlsSsaRead(guard0, controlled, testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }
|
||||
|
||||
@@ -31,68 +31,8 @@ class SemSsaPhiNode extends SemSsaVariable {
|
||||
SemSsaPhiNode() { Specific::phi(this) }
|
||||
|
||||
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
||||
}
|
||||
|
||||
class SemSsaReadPosition instanceof Specific::SsaReadPosition {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
final predicate hasReadOfVar(SemSsaVariable var) { Specific::hasReadOfSsaVariable(this, var) }
|
||||
}
|
||||
|
||||
class SemSsaReadPositionPhiInputEdge extends SemSsaReadPosition {
|
||||
SemBasicBlock origBlock;
|
||||
SemBasicBlock phiBlock;
|
||||
|
||||
SemSsaReadPositionPhiInputEdge() { Specific::phiInputEdge(this, origBlock, phiBlock) }
|
||||
|
||||
predicate phiInput(SemSsaPhiNode phi, SemSsaVariable inp) { Specific::phiInput(this, phi, inp) }
|
||||
|
||||
SemBasicBlock getOrigBlock() { result = origBlock }
|
||||
|
||||
SemBasicBlock getPhiBlock() { result = phiBlock }
|
||||
}
|
||||
|
||||
class SemSsaReadPositionBlock extends SemSsaReadPosition {
|
||||
SemBasicBlock block;
|
||||
|
||||
SemSsaReadPositionBlock() { Specific::readBlock(this, block) }
|
||||
|
||||
SemBasicBlock getBlock() { result = block }
|
||||
|
||||
SemExpr getAnExpr() { result = this.getBlock().getAnExpr() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along a back edge.
|
||||
*/
|
||||
predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge) {
|
||||
edge.phiInput(phi, inp) and
|
||||
// Conservatively assume that every edge is a back edge if we don't have dominance information.
|
||||
(
|
||||
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
|
||||
irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock()) or
|
||||
not edge.getOrigBlock().hasDominanceInformation()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow
|
||||
* graph.
|
||||
*
|
||||
* An ireducible control flow graph is one where the usual dominance-based back edge detection does
|
||||
* not work, because there is a cycle with multiple entry points, meaning there are
|
||||
* mutually-reachable basic blocks where neither dominates the other. For such a graph, we first
|
||||
* remove all detectable back-edges using the normal condition that the predecessor block is
|
||||
* dominated by the successor block, then mark all edges in a cycle in the resulting graph as back
|
||||
* edges.
|
||||
*/
|
||||
private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) {
|
||||
trimmedEdge(b1, b2) and trimmedEdge+(b2, b1)
|
||||
}
|
||||
|
||||
private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) {
|
||||
pred.getASuccessor() = succ and
|
||||
not succ.bbDominates(pred)
|
||||
|
||||
final predicate hasInputFromBlock(SemSsaVariable inp, SemBasicBlock bb) {
|
||||
Specific::phiInputFromBlock(this, inp, bb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,14 +72,14 @@ module Sem implements Semantic {
|
||||
|
||||
class BasicBlock = SemBasicBlock;
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
int getBlockId1(BasicBlock bb) { result = bb.getUniqueId() }
|
||||
|
||||
class Guard = SemGuard;
|
||||
|
||||
predicate implies_v2 = semImplies_v2/4;
|
||||
|
||||
predicate guardDirectlyControlsSsaRead = semGuardDirectlyControlsSsaRead/3;
|
||||
|
||||
predicate guardControlsSsaRead = semGuardControlsSsaRead/3;
|
||||
|
||||
class Type = SemType;
|
||||
|
||||
class IntegerType = SemIntegerType;
|
||||
@@ -94,14 +94,6 @@ module Sem implements Semantic {
|
||||
|
||||
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
||||
|
||||
class SsaReadPosition = SemSsaReadPosition;
|
||||
|
||||
class SsaReadPositionPhiInputEdge = SemSsaReadPositionPhiInputEdge;
|
||||
|
||||
class SsaReadPositionBlock = SemSsaReadPositionBlock;
|
||||
|
||||
predicate backEdge = semBackEdge/3;
|
||||
|
||||
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
||||
SemanticType::conversionCannotOverflow(fromType, toType)
|
||||
}
|
||||
|
||||
@@ -133,33 +133,4 @@ module RangeUtil<DeltaSig D, LangSig<Sem, D> Lang> implements UtilSig<Sem, D> {
|
||||
or
|
||||
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
||||
}
|
||||
|
||||
import Ranking
|
||||
}
|
||||
|
||||
import Ranking
|
||||
|
||||
module Ranking {
|
||||
/**
|
||||
* Holds if `rix` is the number of input edges to `phi`.
|
||||
*/
|
||||
predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
|
||||
rix = max(int r | rankedPhiInput(phi, _, _, r))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
|
||||
* in an arbitrary 1-based numbering of the input edges to `phi`.
|
||||
*/
|
||||
predicate rankedPhiInput(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
|
||||
) {
|
||||
edge.phiInput(phi, inp) and
|
||||
edge =
|
||||
rank[r](SemSsaReadPositionPhiInputEdge e |
|
||||
e.phiInput(phi, _)
|
||||
|
|
||||
e order by e.getOrigBlock().getUniqueId()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||
final override Sign getSign() {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
exists(SemSsaVariable inp, SsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(this, inp) and
|
||||
result = semSsaSign(inp, edge)
|
||||
)
|
||||
@@ -170,11 +170,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
override Sign getSignRestriction() {
|
||||
// Propagate via SSA
|
||||
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
||||
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
|
||||
result = semSsaSign(v, any(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this))
|
||||
or
|
||||
// No block for this read. Just use the sign of the def.
|
||||
// REVIEW: How can this happen?
|
||||
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
|
||||
not exists(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this) and
|
||||
result = semSsaDefSign(v)
|
||||
}
|
||||
}
|
||||
@@ -290,11 +290,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate lowerBound(
|
||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
SemExpr lowerbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(lowerbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
@@ -314,11 +314,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate upperBound(
|
||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
SemExpr upperbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(upperbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
@@ -340,10 +340,10 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* - `isEq = true` : `v = eqbound`
|
||||
* - `isEq = false` : `v != eqbound`
|
||||
*/
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SsaReadPosition pos, boolean isEq) {
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
||||
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
||||
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||
guardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||
e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||
guard.isEquality(eqbound, e, polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
@@ -355,7 +355,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
||||
* order for `v` to be positive.
|
||||
*/
|
||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
@@ -364,7 +364,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
||||
* order for `v` to be negative.
|
||||
*/
|
||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
@@ -373,24 +373,24 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
||||
* can be zero.
|
||||
*/
|
||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, _)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
||||
or
|
||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
@@ -408,7 +408,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
||||
* at `pos`.
|
||||
*/
|
||||
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
|
||||
private predicate hasGuard(SemSsaVariable v, SsaReadPosition pos, Sign s) {
|
||||
s = TPos() and posBound(_, v, pos)
|
||||
or
|
||||
s = TNeg() and negBound(_, v, pos)
|
||||
@@ -421,7 +421,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* might be ruled out by a guard.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
hasGuard(v, pos, result)
|
||||
@@ -432,7 +432,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* can rule it out.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
not hasGuard(v, pos, result)
|
||||
@@ -443,7 +443,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* ruled out the sign but does not.
|
||||
* This does not check that the definition of `v` also allows the sign.
|
||||
*/
|
||||
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private Sign guardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
|
||||
result = TPos() and
|
||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||
or
|
||||
@@ -455,7 +455,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v` at `pos`. */
|
||||
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private Sign semSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||
result = unguardedSsaSign(v, pos)
|
||||
or
|
||||
result = guardedSsaSign(v, pos) and
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||
|
||||
/**
|
||||
* Auxiliary predicate: Types that don't require initialization
|
||||
@@ -33,31 +34,6 @@ predicate allocatedType(Type t) {
|
||||
allocatedType(t.getUnspecifiedType())
|
||||
}
|
||||
|
||||
/**
|
||||
* A declaration of a local variable that leaves the
|
||||
* variable uninitialized.
|
||||
*/
|
||||
DeclStmt declWithNoInit(LocalVariable v) {
|
||||
result.getADeclaration() = v and
|
||||
not exists(v.getInitializer()) and
|
||||
/* The type of the variable is not stack-allocated. */
|
||||
exists(Type t | t = v.getType() | not allocatedType(t))
|
||||
}
|
||||
|
||||
class UninitialisedLocalReachability extends StackVariableReachability {
|
||||
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
// only report the _first_ possibly uninitialized use
|
||||
useOfVarActual(v, node) or
|
||||
definitionBarrier(v, node)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
|
||||
|
||||
@@ -82,8 +58,33 @@ VariableAccess commonException() {
|
||||
containsInlineAssembly(result.getEnclosingFunction())
|
||||
}
|
||||
|
||||
from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
|
||||
predicate isSinkImpl(Instruction sink, VariableAccess va) {
|
||||
exists(LoadInstruction load |
|
||||
va = load.getUnconvertedResultExpression() and
|
||||
not va = commonException() and
|
||||
sink = load.getSourceValue()
|
||||
)
|
||||
}
|
||||
|
||||
class MustFlow extends MustFlowConfiguration {
|
||||
MustFlow() { this = "MustFlow" }
|
||||
|
||||
override predicate isSource(Instruction source) {
|
||||
source instanceof UninitializedInstruction and
|
||||
exists(Type t | t = source.getResultType() | not allocatedType(t))
|
||||
}
|
||||
|
||||
override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
|
||||
|
||||
override predicate allowInterproceduralFlow() { none() }
|
||||
|
||||
override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
|
||||
}
|
||||
|
||||
from
|
||||
VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink
|
||||
where
|
||||
r.reaches(_, v, va) and
|
||||
not va = commonException()
|
||||
conf.hasFlowPath(source, sink) and
|
||||
isSinkImpl(sink.getInstruction(), va) and
|
||||
v = va.getTarget()
|
||||
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -6646,6 +6646,17 @@ WARNING: Module TaintTracking has been deprecated and may be removed in future (
|
||||
| taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | |
|
||||
| taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | |
|
||||
| taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT |
|
||||
| taint.cpp:743:40:743:45 | buffer | taint.cpp:744:5:744:10 | buffer | |
|
||||
| taint.cpp:743:40:743:45 | buffer | taint.cpp:745:27:745:32 | buffer | |
|
||||
| taint.cpp:744:4:744:10 | * ... | taint.cpp:744:3:744:10 | * ... | TAINT |
|
||||
| taint.cpp:744:5:744:10 | buffer | taint.cpp:744:4:744:10 | * ... | TAINT |
|
||||
| taint.cpp:744:14:744:19 | call to source | taint.cpp:744:3:744:21 | ... = ... | |
|
||||
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:743:40:743:45 | buffer | |
|
||||
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:745:3:745:37 | ... = ... | |
|
||||
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:746:10:746:15 | buffer | |
|
||||
| taint.cpp:745:27:745:32 | buffer | taint.cpp:745:19:745:25 | call to realloc | TAINT |
|
||||
| taint.cpp:746:9:746:15 | * ... | taint.cpp:746:8:746:15 | * ... | TAINT |
|
||||
| taint.cpp:746:10:746:15 | buffer | taint.cpp:746:9:746:15 | * ... | TAINT |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
||||
|
||||
@@ -738,4 +738,10 @@ void test_realloc() {
|
||||
char *source = indirect_source();
|
||||
char *dest = (char*)realloc(source, 16);
|
||||
sink(dest); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
void test_realloc_2_indirections(int **buffer) {
|
||||
**buffer = source();
|
||||
buffer = (int**)realloc(buffer, 16);
|
||||
sink(**buffer); // $ ir MISSING: ast
|
||||
}
|
||||
@@ -18,7 +18,7 @@ int test2(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
count = (count+1) % 10;
|
||||
range(count); // $ range=<=9 range=>=-9 range="<=Phi: p | Store: count+1"
|
||||
range(count); // $ range=<=9 range=>=-9
|
||||
}
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
@@ -29,7 +29,7 @@ int test3(struct List* p) {
|
||||
for (; p; p = p->next) {
|
||||
range(count++); // $ range=>=-9 range=<=9
|
||||
count = count % 10;
|
||||
range(count); // $ range=<=9 range=>=-9 range="<=Store: ... +++0" range="<=Phi: p | Store: count+1"
|
||||
range(count); // $ range=<=9 range=>=-9
|
||||
}
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
@@ -317,7 +317,7 @@ int test_mult01(int a, int b) {
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // $ overflow=+- -143 .. 253
|
||||
range(r);
|
||||
total += r; // $ overflow=+
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range=">=... * ...+0"
|
||||
}
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
@@ -365,7 +365,7 @@ int test_mult02(int a, int b) {
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // $ overflow=+- -143 .. 253
|
||||
range(r);
|
||||
total += r; // $ overflow=+
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range=">=... * ...+0"
|
||||
}
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
@@ -460,7 +460,7 @@ int test_mult04(int a, int b) {
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // $ overflow=+- -391 .. 221
|
||||
range(r);
|
||||
total += r; // $ overflow=-
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range="<=... * ...+0"
|
||||
}
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
||||
@@ -508,7 +508,7 @@ int test_mult05(int a, int b) {
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // $ overflow=+- -391 .. 221
|
||||
range(r);
|
||||
total += r; // $ overflow=-
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range="<=... * ...+0"
|
||||
}
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
||||
@@ -974,7 +974,7 @@ void test_mod_neg(int s) {
|
||||
|
||||
void test_mod_ternary(int s, bool b) {
|
||||
int s2 = s % (b ? 5 : 500);
|
||||
range(s2); // $ range=>=-499 range=<=499 range="<=Phi: ... ? ... : ...-1"
|
||||
range(s2); // $ range=>=-499 range=<=499
|
||||
}
|
||||
|
||||
void test_mod_ternary2(int s, bool b1, bool b2) {
|
||||
|
||||
@@ -130,3 +130,19 @@ void test_div(int x) {
|
||||
range(x >> 2); // $ range=>=0 range=<=2
|
||||
}
|
||||
}
|
||||
|
||||
struct X { int n; };
|
||||
void read_argument(const X *);
|
||||
|
||||
// This test exists purely to ensure that modulus analysis terminates in the
|
||||
// presence of inexact phi operands. The LoadInstruction on `while(x->n) { ... }`
|
||||
// reads from a PhiInstruction with two input operands: an exact operand defined
|
||||
// by the StoreInstruction generated by `x->n--` and an inexact operand coming
|
||||
// from the WriteSideEffect generated by `read_argument(x)`. If we don't consider
|
||||
// the inexact operand modulus analysis fails to terminate.
|
||||
void nonterminating_without_operands_as_ssa(X *x) {
|
||||
read_argument(x);
|
||||
while (x->n) {
|
||||
x->n--;
|
||||
}
|
||||
}
|
||||
@@ -22,16 +22,10 @@ edges
|
||||
| test.cpp:52:19:52:37 | call to malloc | test.cpp:53:12:53:23 | ... + ... |
|
||||
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | end |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... |
|
||||
| test.cpp:194:15:194:33 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | ... = ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | ... = ... |
|
||||
| test.cpp:205:15:205:33 | call to malloc | test.cpp:206:17:206:23 | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
|
||||
| test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... |
|
||||
| test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | ... = ... |
|
||||
| test.cpp:260:13:260:24 | new[] | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | * ... |
|
||||
@@ -127,18 +121,10 @@ nodes
|
||||
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
||||
| test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:194:15:194:33 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:201:5:201:19 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:205:15:205:33 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:213:5:213:13 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:231:18:231:30 | new[] | semmle.label | new[] |
|
||||
| test.cpp:232:3:232:20 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:238:20:238:32 | new[] | semmle.label | new[] |
|
||||
| test.cpp:239:5:239:22 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
@@ -220,10 +206,7 @@ subpaths
|
||||
| test.cpp:30:14:30:15 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:32:14:32:21 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:32:14:32:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:37 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:37 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
||||
| test.cpp:201:5:201:19 | ... = ... | test.cpp:194:15:194:33 | call to malloc | test.cpp:201:5:201:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:15:194:33 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
|
||||
| test.cpp:213:5:213:13 | ... = ... | test.cpp:205:15:205:33 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:15:205:33 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
|
||||
| test.cpp:232:3:232:20 | ... = ... | test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:231:18:231:30 | new[] | new[] | test.cpp:232:11:232:15 | index | index |
|
||||
| test.cpp:239:5:239:22 | ... = ... | test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:238:20:238:32 | new[] | new[] | test.cpp:239:13:239:17 | index | index |
|
||||
| test.cpp:264:13:264:14 | * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
||||
| test.cpp:274:5:274:10 | ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
||||
| test.cpp:358:14:358:26 | end_plus_one indirection | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | end_plus_one indirection | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
||||
|
||||
@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
|
||||
return;
|
||||
}
|
||||
|
||||
p[index] = '\0'; // $ deref=L195->L201 // BAD
|
||||
p[index] = '\0'; // $ MISSING: deref=L195->L201 // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test13(unsigned len, unsigned index) {
|
||||
@@ -229,14 +229,14 @@ void test15(unsigned index) {
|
||||
return;
|
||||
}
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // $ alloc=L231 deref=L232 // GOOD [FALSE POSITIVE]
|
||||
newname[index] = 0; // GOOD
|
||||
}
|
||||
|
||||
void test16(unsigned index) {
|
||||
unsigned size = index + 13;
|
||||
if(size >= index) {
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // $ alloc=L238 deref=L239 // GOOD [FALSE POSITIVE]
|
||||
newname[index] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
| test.cpp:12:6:12:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
|
||||
| test.cpp:30:6:30:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:26:6:26:8 | foo | foo |
|
||||
| test.cpp:46:6:46:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:42:6:42:8 | foo | foo |
|
||||
| test.cpp:55:7:55:9 | foo | The variable $@ may not be initialized at this access. | test.cpp:50:6:50:8 | foo | foo |
|
||||
| test.cpp:67:7:67:9 | foo | The variable $@ may not be initialized at this access. | test.cpp:61:6:61:8 | foo | foo |
|
||||
| test.cpp:92:6:92:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:82:6:82:8 | foo | foo |
|
||||
| test.cpp:113:6:113:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
|
||||
| test.cpp:132:9:132:9 | j | The variable $@ may not be initialized at this access. | test.cpp:126:6:126:6 | j | j |
|
||||
| test.cpp:219:3:219:3 | x | The variable $@ may not be initialized at this access. | test.cpp:218:7:218:7 | x | x |
|
||||
| test.cpp:243:13:243:13 | i | The variable $@ may not be initialized at this access. | test.cpp:241:6:241:6 | i | i |
|
||||
| test.cpp:329:9:329:11 | val | The variable $@ may not be initialized at this access. | test.cpp:321:6:321:8 | val | val |
|
||||
| test.cpp:336:10:336:10 | a | The variable $@ may not be initialized at this access. | test.cpp:333:7:333:7 | a | a |
|
||||
| test.cpp:369:10:369:10 | a | The variable $@ may not be initialized at this access. | test.cpp:358:7:358:7 | a | a |
|
||||
| test.cpp:378:9:378:11 | val | The variable $@ may not be initialized at this access. | test.cpp:359:6:359:8 | val | val |
|
||||
|
||||
@@ -27,7 +27,7 @@ void test4(bool b) {
|
||||
if (b) {
|
||||
foo = 1;
|
||||
}
|
||||
use(foo); // BAD
|
||||
use(foo); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test5() {
|
||||
@@ -43,7 +43,7 @@ void test5(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
foo = i;
|
||||
}
|
||||
use(foo); // BAD
|
||||
use(foo); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test6(bool b) {
|
||||
@@ -52,7 +52,7 @@ void test6(bool b) {
|
||||
foo = 42;
|
||||
}
|
||||
if (b) {
|
||||
use(foo); // GOOD (REPORTED, FP)
|
||||
use(foo); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ void test7(bool b) {
|
||||
set = true;
|
||||
}
|
||||
if (set) {
|
||||
use(foo); // GOOD (REPORTED, FP)
|
||||
use(foo); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ void test9(int count) {
|
||||
if (!set) {
|
||||
foo = 42;
|
||||
}
|
||||
use(foo); // GOOD (REPORTED, FP)
|
||||
use(foo); // GOOD
|
||||
}
|
||||
|
||||
void test10() {
|
||||
@@ -129,7 +129,7 @@ int absWrong(int i) {
|
||||
} else if (i < 0) {
|
||||
j = -i;
|
||||
}
|
||||
return j; // wrong: j may not be initialized before use
|
||||
return j; // wrong: j may not be initialized before use [NOT DETECTED]
|
||||
}
|
||||
|
||||
// Example from qhelp
|
||||
@@ -326,7 +326,7 @@ int test28() {
|
||||
a = false;
|
||||
c = false;
|
||||
}
|
||||
return val; // GOOD [FALSE POSITIVE]
|
||||
return val; // GOOD
|
||||
}
|
||||
|
||||
int test29() {
|
||||
@@ -472,4 +472,64 @@ void test44() {
|
||||
int y = 1;
|
||||
|
||||
void(x + y); // BAD
|
||||
}
|
||||
|
||||
enum class State { StateA, StateB, StateC };
|
||||
|
||||
int exhaustive_switch(State s) {
|
||||
int y;
|
||||
switch(s) {
|
||||
case State::StateA:
|
||||
y = 1;
|
||||
break;
|
||||
case State::StateB:
|
||||
y = 2;
|
||||
break;
|
||||
case State::StateC:
|
||||
y = 3;
|
||||
break;
|
||||
}
|
||||
return y; // GOOD (y is always initialized)
|
||||
}
|
||||
|
||||
int exhaustive_switch_2(State s) {
|
||||
int y;
|
||||
switch(s) {
|
||||
case State::StateA:
|
||||
y = 1;
|
||||
break;
|
||||
default:
|
||||
y = 2;
|
||||
break;
|
||||
}
|
||||
return y; // GOOD (y is always initialized)
|
||||
}
|
||||
|
||||
int non_exhaustive_switch(State s) {
|
||||
int y;
|
||||
switch(s) {
|
||||
case State::StateA:
|
||||
y = 1;
|
||||
break;
|
||||
case State::StateB:
|
||||
y = 2;
|
||||
break;
|
||||
}
|
||||
return y; // BAD [NOT DETECTED] (y is not initialized when s = StateC)
|
||||
}
|
||||
|
||||
int non_exhaustive_switch_2(State s) {
|
||||
int y;
|
||||
switch(s) {
|
||||
case State::StateA:
|
||||
y = 1;
|
||||
break;
|
||||
case State::StateB:
|
||||
y = 2;
|
||||
break;
|
||||
}
|
||||
if(s != State::StateC) {
|
||||
return y; // GOOD (y is not initialized when s = StateC, but if s = StateC we won't reach this point)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -27,12 +27,18 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
if (File.Exists(path))
|
||||
{
|
||||
pendingDllsToIndex.Enqueue(path);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
progressMonitor.FindingFiles(path);
|
||||
AddReferenceDirectory(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressMonitor.LogInfo("AssemblyCache: Path not found: " + path);
|
||||
}
|
||||
}
|
||||
IndexReferences();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for parsing project.assets.json files.
|
||||
/// </summary>
|
||||
internal class Assets
|
||||
{
|
||||
private readonly ProgressMonitor progressMonitor;
|
||||
|
||||
private static readonly string[] netFrameworks = new[] {
|
||||
"microsoft.aspnetcore.app.ref",
|
||||
"microsoft.netcore.app.ref",
|
||||
"microsoft.netframework.referenceassemblies",
|
||||
"microsoft.windowsdesktop.app.ref",
|
||||
"netstandard.library.ref"
|
||||
};
|
||||
|
||||
internal Assets(ProgressMonitor progressMonitor)
|
||||
{
|
||||
this.progressMonitor = progressMonitor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class needed for deserializing parts of an assets file.
|
||||
/// It holds information about a reference.
|
||||
///
|
||||
/// Type carries the type of the reference.
|
||||
/// We are only interested in package references.
|
||||
///
|
||||
/// Compile holds information about the files needed for compilation.
|
||||
/// However, if it is a .NET framework reference we assume that all files in the
|
||||
/// package are needed for compilation.
|
||||
/// </summary>
|
||||
private record class ReferenceInfo(string? Type, Dictionary<string, object>? Compile);
|
||||
|
||||
/// <summary>
|
||||
/// Add the package dependencies from the assets file to dependencies.
|
||||
///
|
||||
/// Parse a part of the JSon assets file and add the paths
|
||||
/// to the dependencies required for compilation (and collect
|
||||
/// information about used packages).
|
||||
///
|
||||
/// Example:
|
||||
/// {
|
||||
/// "Castle.Core/4.4.1": {
|
||||
/// "type": "package",
|
||||
/// "compile": {
|
||||
/// "lib/netstandard1.5/Castle.Core.dll": {
|
||||
/// "related": ".xml"
|
||||
/// }
|
||||
/// }
|
||||
/// },
|
||||
/// "Json.Net/1.0.33": {
|
||||
/// "type": "package",
|
||||
/// "compile": {
|
||||
/// "lib/netstandard2.0/Json.Net.dll": {}
|
||||
/// },
|
||||
/// "runtime": {
|
||||
/// "lib/netstandard2.0/Json.Net.dll": {}
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Returns dependencies
|
||||
/// RequiredPaths = {
|
||||
/// "castle.core/4.4.1/lib/netstandard1.5/Castle.Core.dll",
|
||||
/// "json.net/1.0.33/lib/netstandard2.0/Json.Net.dll"
|
||||
/// }
|
||||
/// UsedPackages = {
|
||||
/// "castle.core",
|
||||
/// "json.net"
|
||||
/// }
|
||||
/// </summary>
|
||||
private DependencyContainer AddPackageDependencies(JObject json, DependencyContainer dependencies)
|
||||
{
|
||||
// If there are more than one framework we need to pick just one.
|
||||
// To ensure stability we pick one based on the lexicographic order of
|
||||
// the framework names.
|
||||
var references = json
|
||||
.GetProperty("targets")?
|
||||
.Properties()?
|
||||
.MaxBy(p => p.Name)?
|
||||
.Value
|
||||
.ToObject<Dictionary<string, ReferenceInfo>>();
|
||||
|
||||
if (references is null)
|
||||
{
|
||||
progressMonitor.LogDebug("No references found in the targets section in the assets file.");
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
// Find all the compile dependencies for each reference and
|
||||
// create the relative path to the dependency.
|
||||
references
|
||||
.ForEach(r =>
|
||||
{
|
||||
var info = r.Value;
|
||||
var name = r.Key.ToLowerInvariant();
|
||||
if (info.Type != "package")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a .NET framework reference then include everything.
|
||||
if (netFrameworks.Any(framework => name.StartsWith(framework)))
|
||||
{
|
||||
dependencies.Add(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Compile?
|
||||
.ForEach(r => dependencies.Add(name, r.Key));
|
||||
}
|
||||
});
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse `json` as project.assets.json content and add relative paths to the dependencies
|
||||
/// (together with used package information) required for compilation.
|
||||
/// </summary>
|
||||
/// <returns>True if parsing succeeds, otherwise false.</returns>
|
||||
public bool TryParse(string json, DependencyContainer dependencies)
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JObject.Parse(json);
|
||||
AddPackageDependencies(obj, dependencies);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
progressMonitor.LogDebug($"Failed to parse assets file (unexpected error): {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DependencyContainer GetCompilationDependencies(ProgressMonitor progressMonitor, IEnumerable<string> assets)
|
||||
{
|
||||
var parser = new Assets(progressMonitor);
|
||||
var dependencies = new DependencyContainer();
|
||||
assets.ForEach(asset =>
|
||||
{
|
||||
var json = File.ReadAllText(asset);
|
||||
parser.TryParse(json, dependencies);
|
||||
});
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class JsonExtensions
|
||||
{
|
||||
internal static JObject? GetProperty(this JObject json, string property) =>
|
||||
json[property] as JObject;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
/// <summary>
|
||||
/// Container class for dependencies found in the assets file.
|
||||
/// </summary>
|
||||
internal class DependencyContainer
|
||||
{
|
||||
private readonly List<string> requiredPaths = new();
|
||||
private readonly HashSet<string> usedPackages = new();
|
||||
|
||||
/// <summary>
|
||||
/// In most cases paths in asset files point to dll's or the empty _._ file, which
|
||||
/// is sometimes there to avoid the directory being empty.
|
||||
/// That is, if the path specifically adds a .dll we use that, otherwise we as a fallback
|
||||
/// add the entire directory (which should be fine in case of _._ as well).
|
||||
/// </summary>
|
||||
private static string ParseFilePath(string path)
|
||||
{
|
||||
if (path.EndsWith(".dll"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
return Path.GetDirectoryName(path) ?? path;
|
||||
}
|
||||
|
||||
private static string GetPackageName(string package) =>
|
||||
package
|
||||
.Split(Path.DirectorySeparatorChar)
|
||||
.First();
|
||||
|
||||
/// <summary>
|
||||
/// Paths to dependencies required for compilation.
|
||||
/// </summary>
|
||||
public IEnumerable<string> RequiredPaths => requiredPaths;
|
||||
|
||||
/// <summary>
|
||||
/// Packages that are used as a part of the required dependencies.
|
||||
/// </summary>
|
||||
public HashSet<string> UsedPackages => usedPackages;
|
||||
|
||||
/// <summary>
|
||||
/// Add a dependency inside a package.
|
||||
/// </summary>
|
||||
public void Add(string package, string dependency)
|
||||
{
|
||||
var p = package.Replace('/', Path.DirectorySeparatorChar);
|
||||
var d = dependency.Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
var path = Path.Combine(p, ParseFilePath(d));
|
||||
requiredPaths.Add(path);
|
||||
usedPackages.Add(GetPackageName(p));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a dependency to an entire package
|
||||
/// </summary>
|
||||
public void Add(string package)
|
||||
{
|
||||
var p = package.Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
requiredPaths.Add(p);
|
||||
usedPackages.Add(GetPackageName(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,9 +31,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
private readonly IDotNet dotnet;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly TemporaryDirectory packageDirectory;
|
||||
private readonly TemporaryDirectory missingPackageDirectory;
|
||||
private readonly TemporaryDirectory tempWorkingDirectory;
|
||||
private readonly bool cleanupTempWorkingDirectory;
|
||||
|
||||
private readonly Lazy<Runtime> runtimeLazy;
|
||||
private Runtime Runtime => runtimeLazy.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Performs C# dependency fetching.
|
||||
/// </summary>
|
||||
@@ -48,11 +52,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
this.sourceDir = new DirectoryInfo(srcDir);
|
||||
|
||||
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName));
|
||||
missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "missingpackages"));
|
||||
|
||||
tempWorkingDirectory = new TemporaryDirectory(FileUtils.GetTemporaryWorkingDirectory(out cleanupTempWorkingDirectory));
|
||||
|
||||
try
|
||||
{
|
||||
this.dotnet = DotNet.Make(options, progressMonitor, tempWorkingDirectory);
|
||||
runtimeLazy = new Lazy<Runtime>(() => new Runtime(dotnet));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -74,13 +81,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var solutions = options.SolutionFile is not null
|
||||
? new[] { options.SolutionFile }
|
||||
: allNonBinaryFiles.SelectFileNamesByExtension(".sln");
|
||||
var dllDirNames = options.DllDirs.Count == 0
|
||||
? allFiles.SelectFileNamesByExtension(".dll").ToList()
|
||||
: options.DllDirs.Select(Path.GetFullPath).ToList();
|
||||
var dllPaths = options.DllDirs.Count == 0
|
||||
? allFiles.SelectFileNamesByExtension(".dll").ToHashSet()
|
||||
: options.DllDirs.Select(Path.GetFullPath).ToHashSet();
|
||||
|
||||
if (options.UseNuGet)
|
||||
{
|
||||
dllDirNames.Add(packageDirectory.DirInfo.FullName);
|
||||
try
|
||||
{
|
||||
var nuget = new NugetPackages(sourceDir.FullName, packageDirectory, progressMonitor);
|
||||
@@ -91,40 +97,32 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
progressMonitor.MissingNuGet();
|
||||
}
|
||||
|
||||
var restoredProjects = RestoreSolutions(solutions);
|
||||
var restoredProjects = RestoreSolutions(solutions, out var assets1);
|
||||
var projects = allProjects.Except(restoredProjects);
|
||||
RestoreProjects(projects);
|
||||
DownloadMissingPackages(allNonBinaryFiles);
|
||||
}
|
||||
RestoreProjects(projects, out var assets2);
|
||||
|
||||
var existsNetCoreRefNugetPackage = false;
|
||||
var existsNetFrameworkRefNugetPackage = false;
|
||||
var existsNetstandardLibRefNugetPackage = false;
|
||||
var existsNetstandardLibNugetPackage = false;
|
||||
var dependencies = Assets.GetCompilationDependencies(progressMonitor, assets1.Union(assets2));
|
||||
|
||||
var paths = dependencies
|
||||
.RequiredPaths
|
||||
.Select(d => Path.Combine(packageDirectory.DirInfo.FullName, d))
|
||||
.ToList();
|
||||
dllPaths.UnionWith(paths);
|
||||
|
||||
LogAllUnusedPackages(dependencies);
|
||||
DownloadMissingPackages(allNonBinaryFiles, dllPaths);
|
||||
}
|
||||
|
||||
// Find DLLs in the .Net / Asp.Net Framework
|
||||
// This block needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
|
||||
if (options.ScanNetFrameworkDlls)
|
||||
{
|
||||
existsNetCoreRefNugetPackage = IsNugetPackageAvailable("microsoft.netcore.app.ref");
|
||||
existsNetFrameworkRefNugetPackage = IsNugetPackageAvailable("microsoft.netframework.referenceassemblies");
|
||||
existsNetstandardLibRefNugetPackage = IsNugetPackageAvailable("netstandard.library.ref");
|
||||
existsNetstandardLibNugetPackage = IsNugetPackageAvailable("netstandard.library");
|
||||
|
||||
if (existsNetCoreRefNugetPackage
|
||||
|| existsNetFrameworkRefNugetPackage
|
||||
|| existsNetstandardLibRefNugetPackage
|
||||
|| existsNetstandardLibNugetPackage)
|
||||
{
|
||||
progressMonitor.LogInfo("Found .NET Core/Framework DLLs in NuGet packages. Not adding installation directory.");
|
||||
}
|
||||
else
|
||||
{
|
||||
AddNetFrameworkDlls(dllDirNames);
|
||||
}
|
||||
AddNetFrameworkDlls(dllPaths);
|
||||
AddAspNetCoreFrameworkDlls(dllPaths);
|
||||
AddMicrosoftWindowsDesktopDlls(dllPaths);
|
||||
}
|
||||
|
||||
assemblyCache = new AssemblyCache(dllDirNames, progressMonitor);
|
||||
assemblyCache = new AssemblyCache(dllPaths, progressMonitor);
|
||||
AnalyseSolutions(solutions);
|
||||
|
||||
foreach (var filename in assemblyCache.AllAssemblies.Select(a => a.Filename))
|
||||
@@ -132,7 +130,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
UseReference(filename);
|
||||
}
|
||||
|
||||
RemoveUnnecessaryNugetPackages(existsNetCoreRefNugetPackage, existsNetFrameworkRefNugetPackage, existsNetstandardLibRefNugetPackage, existsNetstandardLibNugetPackage);
|
||||
RemoveNugetAnalyzerReferences();
|
||||
ResolveConflicts();
|
||||
|
||||
// Output the findings
|
||||
@@ -167,58 +165,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
DateTime.Now - startTime);
|
||||
}
|
||||
|
||||
private void RemoveUnnecessaryNugetPackages(bool existsNetCoreRefNugetPackage, bool existsNetFrameworkRefNugetPackage,
|
||||
bool existsNetstandardLibRefNugetPackage, bool existsNetstandardLibNugetPackage)
|
||||
{
|
||||
RemoveNugetAnalyzerReferences();
|
||||
RemoveRuntimeNugetPackageReferences();
|
||||
|
||||
if (fileContent.IsNewProjectStructureUsed
|
||||
&& !fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
// This might have been restored by the CLI even though the project isn't an asp.net core one.
|
||||
RemoveNugetPackageReference("microsoft.aspnetcore.app.ref");
|
||||
}
|
||||
|
||||
// Multiple dotnet framework packages could be present. We keep only one.
|
||||
// The order of the packages is important, we're keeping the first one that is present in the nuget cache.
|
||||
var packagesInPrioOrder = new (bool isPresent, string prefix)[]
|
||||
{
|
||||
// net7.0, ... net5.0, netcoreapp3.1, netcoreapp3.0
|
||||
(existsNetCoreRefNugetPackage, "microsoft.netcore.app.ref"),
|
||||
// net48, ..., net20
|
||||
(existsNetFrameworkRefNugetPackage, "microsoft.netframework.referenceassemblies."),
|
||||
// netstandard2.1
|
||||
(existsNetstandardLibRefNugetPackage, "netstandard.library.ref"),
|
||||
// netstandard2.0
|
||||
(existsNetstandardLibNugetPackage, "netstandard.library")
|
||||
};
|
||||
|
||||
for (var i = 0; i < packagesInPrioOrder.Length; i++)
|
||||
{
|
||||
var (isPresent, _) = packagesInPrioOrder[i];
|
||||
if (!isPresent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Package is present, remove all the lower priority packages:
|
||||
for (var j = i + 1; j < packagesInPrioOrder.Length; j++)
|
||||
{
|
||||
var (otherIsPresent, otherPrefix) = packagesInPrioOrder[j];
|
||||
if (otherIsPresent)
|
||||
{
|
||||
RemoveNugetPackageReference(otherPrefix);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: There could be multiple `microsoft.netframework.referenceassemblies` packages,
|
||||
// we could keep the newest one, but this is covered by the conflict resolution logic
|
||||
// (if the file names match)
|
||||
}
|
||||
|
||||
private void RemoveNugetAnalyzerReferences()
|
||||
{
|
||||
if (!options.UseNuGet)
|
||||
@@ -258,58 +204,58 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
}
|
||||
private void AddNetFrameworkDlls(List<string> dllDirNames)
|
||||
|
||||
private void AddNetFrameworkDlls(ISet<string> dllPaths)
|
||||
{
|
||||
var runtime = new Runtime(dotnet);
|
||||
// Multiple dotnet framework packages could be present.
|
||||
// The order of the packages is important, we're adding the first one that is present in the nuget cache.
|
||||
var packagesInPrioOrder = new string[]
|
||||
{
|
||||
"microsoft.netcore.app.ref", // net7.0, ... net5.0, netcoreapp3.1, netcoreapp3.0
|
||||
"microsoft.netframework.referenceassemblies.", // net48, ..., net20
|
||||
"netstandard.library.ref", // netstandard2.1
|
||||
"netstandard.library" // netstandard2.0
|
||||
};
|
||||
|
||||
var frameworkPath = packagesInPrioOrder
|
||||
.Select((s, index) => (Index: index, Path: GetPackageDirectory(s)))
|
||||
.FirstOrDefault(pair => pair.Path is not null);
|
||||
|
||||
if (frameworkPath.Path is not null)
|
||||
{
|
||||
dllPaths.Add(frameworkPath.Path);
|
||||
progressMonitor.LogInfo($"Found .NET Core/Framework DLLs in NuGet packages at {frameworkPath.Path}. Not adding installation directory.");
|
||||
|
||||
for (var i = frameworkPath.Index + 1; i < packagesInPrioOrder.Length; i++)
|
||||
{
|
||||
RemoveNugetPackageReference(packagesInPrioOrder[i], dllPaths);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string? runtimeLocation = null;
|
||||
|
||||
if (options.UseSelfContainedDotnet)
|
||||
{
|
||||
runtimeLocation = runtime.ExecutingRuntime;
|
||||
runtimeLocation = Runtime.ExecutingRuntime;
|
||||
}
|
||||
else if (fileContent.IsNewProjectStructureUsed)
|
||||
{
|
||||
runtimeLocation = runtime.NetCoreRuntime;
|
||||
runtimeLocation = Runtime.NetCoreRuntime;
|
||||
}
|
||||
else if (fileContent.IsLegacyProjectStructureUsed)
|
||||
{
|
||||
runtimeLocation = runtime.DesktopRuntime;
|
||||
runtimeLocation = Runtime.DesktopRuntime;
|
||||
}
|
||||
|
||||
runtimeLocation ??= runtime.ExecutingRuntime;
|
||||
runtimeLocation ??= Runtime.ExecutingRuntime;
|
||||
|
||||
progressMonitor.LogInfo($".NET runtime location selected: {runtimeLocation}");
|
||||
dllDirNames.Add(runtimeLocation);
|
||||
|
||||
if (fileContent.IsNewProjectStructureUsed
|
||||
&& fileContent.UseAspNetCoreDlls
|
||||
&& runtime.AspNetCoreRuntime is string aspRuntime)
|
||||
{
|
||||
progressMonitor.LogInfo($"ASP.NET runtime location selected: {aspRuntime}");
|
||||
dllDirNames.Add(aspRuntime);
|
||||
}
|
||||
dllPaths.Add(runtimeLocation);
|
||||
}
|
||||
|
||||
private void RemoveRuntimeNugetPackageReferences()
|
||||
{
|
||||
var runtimePackagePrefixes = new[]
|
||||
{
|
||||
"microsoft.netcore.app.runtime",
|
||||
"microsoft.aspnetcore.app.runtime",
|
||||
"microsoft.windowsdesktop.app.runtime",
|
||||
|
||||
// legacy runtime packages:
|
||||
"runtime.linux-x64.microsoft.netcore.app",
|
||||
"runtime.osx-x64.microsoft.netcore.app",
|
||||
"runtime.win-x64.microsoft.netcore.app",
|
||||
|
||||
// Internal implementation packages not meant for direct consumption:
|
||||
"runtime."
|
||||
};
|
||||
RemoveNugetPackageReference(runtimePackagePrefixes);
|
||||
}
|
||||
|
||||
private void RemoveNugetPackageReference(params string[] packagePrefixes)
|
||||
private void RemoveNugetPackageReference(string packagePrefix, ISet<string> dllPaths)
|
||||
{
|
||||
if (!options.UseNuGet)
|
||||
{
|
||||
@@ -322,32 +268,74 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return;
|
||||
}
|
||||
|
||||
var packagePathPrefixes = packagePrefixes.Select(p => Path.Combine(packageFolder, p.ToLowerInvariant()));
|
||||
|
||||
foreach (var filename in usedReferences.Keys)
|
||||
var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
|
||||
var toRemove = dllPaths.Where(s => s.ToLowerInvariant().StartsWith(packagePathPrefix));
|
||||
foreach (var path in toRemove)
|
||||
{
|
||||
var lowerFilename = filename.ToLowerInvariant();
|
||||
|
||||
if (packagePathPrefixes.Any(prefix => lowerFilename.StartsWith(prefix)))
|
||||
{
|
||||
usedReferences.Remove(filename);
|
||||
progressMonitor.RemovedReference(filename);
|
||||
}
|
||||
dllPaths.Remove(path);
|
||||
progressMonitor.RemovedReference(path);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsNugetPackageAvailable(string packagePrefix)
|
||||
private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths)
|
||||
{
|
||||
if (!fileContent.IsNewProjectStructureUsed || !fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// First try to find ASP.NET Core assemblies in the NuGet packages
|
||||
if (GetPackageDirectory("microsoft.aspnetcore.app.ref") is string aspNetCorePackage)
|
||||
{
|
||||
progressMonitor.LogInfo($"Found ASP.NET Core in NuGet packages. Not adding installation directory.");
|
||||
dllPaths.Add(aspNetCorePackage);
|
||||
}
|
||||
else if (Runtime.AspNetCoreRuntime is string aspNetCoreRuntime)
|
||||
{
|
||||
progressMonitor.LogInfo($"ASP.NET runtime location selected: {aspNetCoreRuntime}");
|
||||
dllPaths.Add(aspNetCoreRuntime);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddMicrosoftWindowsDesktopDlls(ISet<string> dllPaths)
|
||||
{
|
||||
if (GetPackageDirectory("microsoft.windowsdesktop.app.ref") is string windowsDesktopApp)
|
||||
{
|
||||
progressMonitor.LogInfo($"Found Windows Desktop App in NuGet packages.");
|
||||
dllPaths.Add(windowsDesktopApp);
|
||||
}
|
||||
}
|
||||
|
||||
private string? GetPackageDirectory(string packagePrefix)
|
||||
{
|
||||
if (!options.UseNuGet)
|
||||
{
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DirectoryInfo(packageDirectory.DirInfo.FullName)
|
||||
.EnumerateDirectories(packagePrefix + "*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
|
||||
.Any();
|
||||
.FirstOrDefault()?
|
||||
.FullName;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetAllPackageDirectories()
|
||||
{
|
||||
if (!options.UseNuGet)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
return new DirectoryInfo(packageDirectory.DirInfo.FullName)
|
||||
.EnumerateDirectories("*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
|
||||
.Select(d => d.FullName);
|
||||
}
|
||||
|
||||
private void LogAllUnusedPackages(DependencyContainer dependencies) =>
|
||||
GetAllPackageDirectories()
|
||||
.Where(package => !dependencies.UsedPackages.Contains(package))
|
||||
.ForEach(package => progressMonitor.LogInfo($"Unused package: {package}"));
|
||||
|
||||
private void GenerateSourceFileFromImplicitUsings()
|
||||
{
|
||||
var usings = new HashSet<string>();
|
||||
@@ -437,7 +425,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// 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)
|
||||
private static string ComputeTempDirectory(string srcDir, string packages = "packages")
|
||||
{
|
||||
var bytes = Encoding.Unicode.GetBytes(srcDir);
|
||||
var sha = SHA1.HashData(bytes);
|
||||
@@ -445,7 +433,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
foreach (var b in sha.Take(8))
|
||||
sb.AppendFormat("{0:x2}", b);
|
||||
|
||||
return Path.Combine(Path.GetTempPath(), "GitHub", "packages", sb.ToString());
|
||||
return Path.Combine(Path.GetTempPath(), "GitHub", packages, sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -623,41 +611,52 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
}
|
||||
|
||||
private bool RestoreProject(string project, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null) =>
|
||||
dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching, pathToNugetConfig);
|
||||
private bool RestoreProject(string project, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, string? pathToNugetConfig = null) =>
|
||||
dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching, out assets, pathToNugetConfig);
|
||||
|
||||
private bool RestoreSolution(string solution, out IEnumerable<string> projects) =>
|
||||
dotnet.RestoreSolutionToDirectory(solution, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: true, out projects);
|
||||
private bool RestoreSolution(string solution, out IEnumerable<string> projects, out IEnumerable<string> assets) =>
|
||||
dotnet.RestoreSolutionToDirectory(solution, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: true, out projects, out assets);
|
||||
|
||||
/// <summary>
|
||||
/// Executes `dotnet restore` on all solution files in solutions.
|
||||
/// As opposed to RestoreProjects this is not run in parallel using PLINQ
|
||||
/// as `dotnet restore` on a solution already uses multiple threads for restoring
|
||||
/// the projects (this can be disabled with the `--disable-parallel` flag).
|
||||
/// 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) =>
|
||||
solutions.SelectMany(solution =>
|
||||
private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out IEnumerable<string> assets)
|
||||
{
|
||||
var assetFiles = new List<string>();
|
||||
var projects = solutions.SelectMany(solution =>
|
||||
{
|
||||
RestoreSolution(solution, out var restoredProjects);
|
||||
RestoreSolution(solution, out var restoredProjects, out var a);
|
||||
assetFiles.AddRange(a);
|
||||
return restoredProjects;
|
||||
});
|
||||
assets = assetFiles;
|
||||
return projects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes `dotnet restore` on all projects in projects.
|
||||
/// This is done in parallel for performance reasons.
|
||||
/// Populates assets with the relative paths to the assets files generated by the restore.
|
||||
/// </summary>
|
||||
/// <param name="projects">A list of paths to project files.</param>
|
||||
private void RestoreProjects(IEnumerable<string> projects)
|
||||
private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<string> assets)
|
||||
{
|
||||
var assetFiles = new List<string>();
|
||||
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, project =>
|
||||
{
|
||||
RestoreProject(project, forceDotnetRefAssemblyFetching: true);
|
||||
RestoreProject(project, forceDotnetRefAssemblyFetching: true, out var a);
|
||||
assetFiles.AddRange(a);
|
||||
});
|
||||
assets = assetFiles;
|
||||
}
|
||||
|
||||
private void DownloadMissingPackages(List<FileInfo> allFiles)
|
||||
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths)
|
||||
{
|
||||
var nugetConfigs = allFiles.SelectFileNamesByName("nuget.config").ToArray();
|
||||
string? nugetConfig = null;
|
||||
@@ -698,13 +697,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return;
|
||||
}
|
||||
|
||||
success = RestoreProject(tempDir.DirInfo.FullName, forceDotnetRefAssemblyFetching: false, pathToNugetConfig: nugetConfig);
|
||||
dotnet.RestoreProjectToDirectory(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: false, out var _, pathToNugetConfig: nugetConfig);
|
||||
// TODO: the restore might fail, we could retry with a prerelease (*-* instead of *) version of the package.
|
||||
if (!success)
|
||||
{
|
||||
progressMonitor.FailedToRestoreNugetPackage(package);
|
||||
}
|
||||
});
|
||||
|
||||
dllPaths.Add(missingPackageDirectory.DirInfo.FullName);
|
||||
}
|
||||
|
||||
private void AnalyseSolutions(IEnumerable<string> solutions)
|
||||
@@ -724,26 +725,25 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public void Dispose(TemporaryDirectory? dir, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
packageDirectory?.Dispose();
|
||||
dir?.Dispose();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
progressMonitor.LogInfo("Couldn't delete package directory: " + exc.Message);
|
||||
progressMonitor.LogInfo($"Couldn't delete {name} directory {exc.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(packageDirectory, "package");
|
||||
Dispose(missingPackageDirectory, "missing package");
|
||||
if (cleanupTempWorkingDirectory)
|
||||
{
|
||||
try
|
||||
{
|
||||
tempWorkingDirectory?.Dispose();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
progressMonitor.LogInfo("Couldn't delete temporary working directory: " + exc.Message);
|
||||
}
|
||||
Dispose(tempWorkingDirectory, "temporary working");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private string GetRestoreArgs(string projectOrSolutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching)
|
||||
{
|
||||
var args = $"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true";
|
||||
var args = $"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal";
|
||||
|
||||
if (forceDotnetRefAssemblyFetching)
|
||||
{
|
||||
@@ -60,7 +60,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return args;
|
||||
}
|
||||
|
||||
public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null)
|
||||
private static IEnumerable<string> GetFirstGroupOnMatch(Regex regex, IEnumerable<string> lines) =>
|
||||
lines
|
||||
.Select(line => regex.Match(line))
|
||||
.Where(match => match.Success)
|
||||
.Select(match => match.Groups[1].Value);
|
||||
|
||||
private static IEnumerable<string> GetAssetsFilePaths(IEnumerable<string> lines) =>
|
||||
GetFirstGroupOnMatch(AssetsFileRegex(), lines);
|
||||
|
||||
private static IEnumerable<string> GetRestoredProjects(IEnumerable<string> lines) =>
|
||||
GetFirstGroupOnMatch(RestoredProjectRegex(), lines);
|
||||
|
||||
public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, string? pathToNugetConfig = null)
|
||||
{
|
||||
var args = GetRestoreArgs(projectFile, packageDirectory, forceDotnetRefAssemblyFetching);
|
||||
if (pathToNugetConfig != null)
|
||||
@@ -68,25 +80,18 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
args += $" --configfile \"{pathToNugetConfig}\"";
|
||||
}
|
||||
|
||||
return dotnetCliInvoker.RunCommand(args);
|
||||
var success = dotnetCliInvoker.RunCommand(args, out var output);
|
||||
assets = success ? GetAssetsFilePaths(output) : Array.Empty<string>();
|
||||
return success;
|
||||
}
|
||||
|
||||
public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects)
|
||||
public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects, out IEnumerable<string> assets)
|
||||
{
|
||||
var args = GetRestoreArgs(solutionFile, packageDirectory, forceDotnetRefAssemblyFetching);
|
||||
args += " --verbosity normal";
|
||||
if (dotnetCliInvoker.RunCommand(args, out var output))
|
||||
{
|
||||
var regex = RestoreProjectRegex();
|
||||
projects = output
|
||||
.Select(line => regex.Match(line))
|
||||
.Where(match => match.Success)
|
||||
.Select(match => match.Groups[1].Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
projects = Array.Empty<string>();
|
||||
return false;
|
||||
var success = dotnetCliInvoker.RunCommand(args, out var output);
|
||||
projects = success ? GetRestoredProjects(output) : Array.Empty<string>();
|
||||
assets = success ? GetAssetsFilePaths(output) : Array.Empty<string>();
|
||||
return success;
|
||||
}
|
||||
|
||||
public bool New(string folder)
|
||||
@@ -121,6 +126,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
|
||||
[GeneratedRegex("Restored\\s+(.+\\.csproj)", RegexOptions.Compiled)]
|
||||
private static partial Regex RestoreProjectRegex();
|
||||
private static partial Regex RestoredProjectRegex();
|
||||
|
||||
[GeneratedRegex("[Assets\\sfile\\shas\\snot\\schanged.\\sSkipping\\sassets\\sfile\\swriting.|Writing\\sassets\\sfile\\sto\\sdisk.]\\sPath:\\s(.*)", RegexOptions.Compiled)]
|
||||
private static partial Regex AssetsFileRegex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal interface IDotNet
|
||||
{
|
||||
bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null);
|
||||
bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects);
|
||||
bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, string? pathToNugetConfig = null);
|
||||
bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects, out IEnumerable<string> assets);
|
||||
bool New(string folder);
|
||||
bool AddPackage(string folder, string package);
|
||||
IList<string> GetListedRuntimes();
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
// The current argument is not named
|
||||
// so the previous ones were also not named
|
||||
// so the child index matches the parameter index.
|
||||
isParamsParameter = Symbol?.AttributeConstructor?.Parameters[childIndex].IsParams == true;
|
||||
isParamsParameter = Symbol.AttributeConstructor?.Parameters[childIndex].IsParams == true;
|
||||
argSyntax = ctorArguments[childIndex];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Position.Span.Start.Line + 1, Position.Span.Start.Character + 1,
|
||||
Position.Span.End.Line + 1, Position.Span.End.Character);
|
||||
|
||||
var mapped = Symbol!.GetMappedLineSpan();
|
||||
var mapped = Symbol.GetMappedLineSpan();
|
||||
if (mapped.HasMappedPath && mapped.IsValid)
|
||||
{
|
||||
var mappedLoc = Create(Context, Location.Create(mapped.Path, default, mapped.Span));
|
||||
|
||||
206
csharp/extractor/Semmle.Extraction.Tests/Assets.cs
Normal file
206
csharp/extractor/Semmle.Extraction.Tests/Assets.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using Xunit;
|
||||
using System.Linq;
|
||||
using Semmle.Extraction.CSharp.DependencyFetching;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
public class AssetsTests
|
||||
{
|
||||
private static string FixExpectedPathOnWindows(string path) => path.Replace('\\', '/');
|
||||
|
||||
[Fact]
|
||||
public void TestAssets1()
|
||||
{
|
||||
// Setup
|
||||
var assets = new Assets(new ProgressMonitor(new LoggerStub()));
|
||||
var json = assetsJson1;
|
||||
var dependencies = new DependencyContainer();
|
||||
|
||||
// Execute
|
||||
var success = assets.TryParse(json, dependencies);
|
||||
|
||||
// Verify
|
||||
Assert.True(success);
|
||||
Assert.Equal(5, dependencies.RequiredPaths.Count());
|
||||
Assert.Equal(4, dependencies.UsedPackages.Count());
|
||||
|
||||
var normalizedPaths = dependencies.RequiredPaths.Select(FixExpectedPathOnWindows);
|
||||
// Required references
|
||||
Assert.Contains("castle.core/4.4.1/lib/netstandard1.5/Castle.Core.dll", normalizedPaths);
|
||||
Assert.Contains("castle.core/4.4.1/lib/netstandard1.5/Castle.Core2.dll", normalizedPaths);
|
||||
Assert.Contains("json.net/1.0.33/lib/netstandard2.0/Json.Net.dll", normalizedPaths);
|
||||
Assert.Contains("microsoft.aspnetcore.cryptography.internal/6.0.8/lib/net6.0/Microsoft.AspNetCore.Cryptography.Internal.dll", normalizedPaths);
|
||||
Assert.Contains("humanizer.core/2.8.26/lib/netstandard2.0", normalizedPaths);
|
||||
// Used packages
|
||||
Assert.Contains("castle.core", dependencies.UsedPackages);
|
||||
Assert.Contains("json.net", dependencies.UsedPackages);
|
||||
Assert.Contains("microsoft.aspnetcore.cryptography.internal", dependencies.UsedPackages);
|
||||
Assert.Contains("humanizer.core", dependencies.UsedPackages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAssets2()
|
||||
{
|
||||
// Setup
|
||||
var assets = new Assets(new ProgressMonitor(new LoggerStub()));
|
||||
var json = assetsJson2;
|
||||
var dependencies = new DependencyContainer();
|
||||
|
||||
// Execute
|
||||
var success = assets.TryParse(json, dependencies);
|
||||
|
||||
// Verify
|
||||
Assert.True(success);
|
||||
Assert.Equal(2, dependencies.RequiredPaths.Count());
|
||||
|
||||
var normalizedPaths = dependencies.RequiredPaths.Select(FixExpectedPathOnWindows);
|
||||
// Required references
|
||||
Assert.Contains("microsoft.netframework.referenceassemblies/1.0.3", normalizedPaths);
|
||||
Assert.Contains("microsoft.netframework.referenceassemblies.net48/1.0.3", normalizedPaths);
|
||||
// Used packages
|
||||
Assert.Contains("microsoft.netframework.referenceassemblies", dependencies.UsedPackages);
|
||||
Assert.Contains("microsoft.netframework.referenceassemblies.net48", dependencies.UsedPackages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAssets3()
|
||||
{
|
||||
// Setup
|
||||
var assets = new Assets(new ProgressMonitor(new LoggerStub()));
|
||||
var json = "garbage data";
|
||||
var dependencies = new DependencyContainer();
|
||||
|
||||
// Execute
|
||||
var success = assets.TryParse(json, dependencies);
|
||||
|
||||
// Verify
|
||||
Assert.False(success);
|
||||
Assert.Empty(dependencies.RequiredPaths);
|
||||
}
|
||||
|
||||
private readonly string assetsJson1 = """
|
||||
{
|
||||
"version": 3,
|
||||
"targets": {
|
||||
"net7.0": {
|
||||
"Castle.Core/4.4.1": {
|
||||
"type": "package",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.1",
|
||||
"System.Collections.Specialized": "4.3.0",
|
||||
},
|
||||
"compile": {
|
||||
"lib/netstandard1.5/Castle.Core.dll": {
|
||||
"related": ".xml"
|
||||
},
|
||||
"lib/netstandard1.5/Castle.Core2.dll": {
|
||||
"related": ".xml"
|
||||
}
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.5/Castle.Core.dll": {
|
||||
"related": ".xml"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Json.Net/1.0.33": {
|
||||
"type": "package",
|
||||
"compile": {
|
||||
"lib/netstandard2.0/Json.Net.dll": {}
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Json.Net.dll": {}
|
||||
}
|
||||
},
|
||||
"MessagePackAnalyzer/2.1.152": {
|
||||
"type": "package"
|
||||
},
|
||||
"Microsoft.AspNetCore.Cryptography.Internal/6.0.8": {
|
||||
"type": "package",
|
||||
"compile": {
|
||||
"lib/net6.0/Microsoft.AspNetCore.Cryptography.Internal.dll": {
|
||||
"related": ".xml"
|
||||
}
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net6.0/Microsoft.AspNetCore.Cryptography.Internal.dll": {
|
||||
"related": ".xml"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Humanizer.Core/2.8.26": {
|
||||
"type": "package",
|
||||
"compile": {
|
||||
"lib/netstandard2.0/_._": {
|
||||
"related": ".xml"
|
||||
}
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Humanizer.dll": {
|
||||
"related": ".xml"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Nop.Core/4.5.0": {
|
||||
"type": "project",
|
||||
"compile": {
|
||||
"bin/placeholder/Nop.Core.dll": {}
|
||||
},
|
||||
"runtime": {
|
||||
"bin/placeholder/Nop.Core.dll": {}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"project": {
|
||||
"version": "1.0.0",
|
||||
"frameworks": {
|
||||
"net7.0": {
|
||||
"targetAlias": "net7.0",
|
||||
"downloadDependencies": [
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App.Ref",
|
||||
"version": "[7.0.2, 7.0.2]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.NETCore.App.Ref",
|
||||
"version": "[7.0.2, 7.0.2]"
|
||||
}
|
||||
],
|
||||
"frameworkReferences": {
|
||||
"Microsoft.AspNetCore.App": {
|
||||
"privateAssets": "none"
|
||||
},
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private readonly string assetsJson2 = """
|
||||
{
|
||||
"version": 3,
|
||||
"targets": {
|
||||
".NETFramework,Version=v4.8": {
|
||||
"Microsoft.NETFramework.ReferenceAssemblies/1.0.3": {
|
||||
"type": "package",
|
||||
"dependencies": {
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net48": "1.0.3"
|
||||
}
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net48/1.0.3": {
|
||||
"type": "package",
|
||||
"build": {
|
||||
"build/Microsoft.NETFramework.ReferenceAssemblies.net48.targets": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -43,9 +43,11 @@ namespace Semmle.Extraction.Tests
|
||||
private static IList<string> MakeDotnetRestoreOutput() =>
|
||||
new List<string> {
|
||||
" Determining projects to restore...",
|
||||
" Writing assets file to disk. Path: /path/to/project.assets.json",
|
||||
" Restored /path/to/project.csproj (in 1.23 sec).",
|
||||
" Other output...",
|
||||
" More output...",
|
||||
" Assets file has not changed. Skipping assets file writing. Path: /path/to/project2.assets.json",
|
||||
" Restored /path/to/project2.csproj (in 4.56 sec).",
|
||||
" Other output...",
|
||||
};
|
||||
@@ -99,26 +101,29 @@ namespace Semmle.Extraction.Tests
|
||||
var dotnet = MakeDotnet(dotnetCliInvoker);
|
||||
|
||||
// Execute
|
||||
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false);
|
||||
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, out var assets);
|
||||
|
||||
// Verify
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
Assert.Equal("restore --no-dependencies \"myproject.csproj\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true", lastArgs);
|
||||
Assert.Equal("restore --no-dependencies \"myproject.csproj\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal", lastArgs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDotnetRestoreProjectToDirectory2()
|
||||
{
|
||||
// Setup
|
||||
var dotnetCliInvoker = new DotNetCliInvokerStub(new List<string>());
|
||||
var dotnetCliInvoker = new DotNetCliInvokerStub(MakeDotnetRestoreOutput());
|
||||
var dotnet = MakeDotnet(dotnetCliInvoker);
|
||||
|
||||
// Execute
|
||||
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, "myconfig.config");
|
||||
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, out var assets, "myconfig.config");
|
||||
|
||||
// Verify
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
Assert.Equal("restore --no-dependencies \"myproject.csproj\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --configfile \"myconfig.config\"", lastArgs);
|
||||
Assert.Equal("restore --no-dependencies \"myproject.csproj\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile \"myconfig.config\"", lastArgs);
|
||||
Assert.Equal(2, assets.Count());
|
||||
Assert.Contains("/path/to/project.assets.json", assets);
|
||||
Assert.Contains("/path/to/project2.assets.json", assets);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -129,7 +134,7 @@ namespace Semmle.Extraction.Tests
|
||||
var dotnet = MakeDotnet(dotnetCliInvoker);
|
||||
|
||||
// Execute
|
||||
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects);
|
||||
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects, out var assets);
|
||||
|
||||
// Verify
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
@@ -137,6 +142,9 @@ namespace Semmle.Extraction.Tests
|
||||
Assert.Equal(2, projects.Count());
|
||||
Assert.Contains("/path/to/project.csproj", projects);
|
||||
Assert.Contains("/path/to/project2.csproj", projects);
|
||||
Assert.Equal(2, assets.Count());
|
||||
Assert.Contains("/path/to/project.assets.json", assets);
|
||||
Assert.Contains("/path/to/project2.assets.json", assets);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -148,12 +156,13 @@ namespace Semmle.Extraction.Tests
|
||||
dotnetCliInvoker.Success = false;
|
||||
|
||||
// Execute
|
||||
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects);
|
||||
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects, out var assets);
|
||||
|
||||
// Verify
|
||||
var lastArgs = dotnetCliInvoker.GetLastArgs();
|
||||
Assert.Equal("restore --no-dependencies \"mysolution.sln\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal", lastArgs);
|
||||
Assert.Empty(projects);
|
||||
Assert.Empty(assets);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -19,11 +19,16 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
public bool New(string folder) => true;
|
||||
|
||||
public bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null) => true;
|
||||
public bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, string? pathToNugetConfig = null)
|
||||
{
|
||||
assets = Array.Empty<string>();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RestoreSolutionToDirectory(string solution, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects)
|
||||
public bool RestoreSolutionToDirectory(string solution, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects, out IEnumerable<string> assets)
|
||||
{
|
||||
projects = Array.Empty<string>();
|
||||
assets = Array.Empty<string>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
@@ -30,6 +31,7 @@ namespace Semmle.Extraction
|
||||
/// <typeparam name="TSymbol">The type of the symbol.</typeparam>
|
||||
public abstract class CachedEntity<TSymbol> : CachedEntity where TSymbol : notnull
|
||||
{
|
||||
[NotNull]
|
||||
public TSymbol Symbol { get; }
|
||||
|
||||
protected CachedEntity(Context context, TSymbol symbol) : base(context)
|
||||
|
||||
@@ -113,5 +113,11 @@ namespace Semmle.Util
|
||||
h = h * 7 + i.GetHashCode();
|
||||
return h;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the sequence with nulls removed.
|
||||
/// </summary>
|
||||
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> items) where T : class =>
|
||||
items.Where(i => i is not null)!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -14,4 +13,9 @@
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
|
||||
<RemoveDir Directories=".\bin" />
|
||||
<RemoveDir Directories=".\obj" />
|
||||
<RemoveDir Directories=".\myout" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -8,3 +8,8 @@ check_diagnostics()
|
||||
# Explicitly build and then run tests.
|
||||
run_codeql_database_create(['dotnet clean', 'rm -rf test-db', 'dotnet build -o myout', 'dotnet test myout/dotnet_test.dll'], test_db="test2-db", lang="csharp")
|
||||
check_diagnostics(test_db="test2-db")
|
||||
|
||||
thisDir = os.path.abspath(os.getcwd())
|
||||
# Explicit build and then run tests using the absolute path.
|
||||
run_codeql_database_create(['dotnet clean', 'rm -rf test2-db', 'dotnet build -o myout', f'dotnet test {thisDir}/myout/dotnet_test.dll'], test_db="test3-db", lang="csharp")
|
||||
check_diagnostics(test_db="test3-db")
|
||||
@@ -1,7 +1,3 @@
|
||||
| /avalara.avatax/21.10.0/lib/net20/Avalara.AvaTax.RestClient.net20.dll |
|
||||
| /avalara.avatax/21.10.0/lib/net45/Avalara.AvaTax.RestClient.net45.dll |
|
||||
| /avalara.avatax/21.10.0/lib/net461/Avalara.AvaTax.RestClient.net461.dll |
|
||||
| /avalara.avatax/21.10.0/lib/netstandard16/Avalara.AvaTax.netstandard11.dll |
|
||||
| /avalara.avatax/21.10.0/lib/netstandard20/Avalara.AvaTax.netstandard20.dll |
|
||||
| /microsoft.bcl.asyncinterfaces/6.0.0/lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll |
|
||||
| /microsoft.netcore.app.ref/3.1.0/ref/netcoreapp3.1/System.Runtime.InteropServices.WindowsRuntime.dll |
|
||||
@@ -168,4 +164,4 @@
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/WindowsBase.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/mscorlib.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/netstandard.dll |
|
||||
| /newtonsoft.json/12.0.1/lib/portable-net45+win8+wp8+wpa81/Newtonsoft.Json.dll |
|
||||
| /newtonsoft.json/12.0.1/lib/netstandard2.0/Newtonsoft.Json.dll |
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/Microsoft.CSharp.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/Microsoft.VisualBasic.Core.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/Microsoft.VisualBasic.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/Microsoft.Win32.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/Microsoft.Win32.Registry.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.AppContext.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Buffers.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Collections.Concurrent.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Collections.Immutable.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Collections.NonGeneric.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Collections.Specialized.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Collections.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ComponentModel.Annotations.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ComponentModel.DataAnnotations.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ComponentModel.EventBasedAsync.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ComponentModel.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ComponentModel.TypeConverter.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ComponentModel.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Configuration.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Console.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Core.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Data.Common.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Data.DataSetExtensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Data.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.Contracts.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.Debug.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.DiagnosticSource.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.FileVersionInfo.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.Process.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.StackTrace.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.TextWriterTraceListener.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.Tools.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.TraceSource.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Diagnostics.Tracing.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Drawing.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Drawing.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Dynamic.Runtime.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Formats.Asn1.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Formats.Tar.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Globalization.Calendars.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Globalization.Extensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Globalization.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.Compression.Brotli.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.Compression.FileSystem.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.Compression.ZipFile.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.Compression.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.FileSystem.AccessControl.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.FileSystem.DriveInfo.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.FileSystem.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.FileSystem.Watcher.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.FileSystem.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.IsolatedStorage.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.MemoryMappedFiles.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.Pipes.AccessControl.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.Pipes.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.UnmanagedMemoryStream.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.IO.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Linq.Expressions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Linq.Parallel.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Linq.Queryable.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Linq.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Memory.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Http.Json.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Http.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.HttpListener.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Mail.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.NameResolution.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.NetworkInformation.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Ping.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Quic.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Requests.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Security.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.ServicePoint.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.Sockets.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.WebClient.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.WebHeaderCollection.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.WebProxy.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.WebSockets.Client.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.WebSockets.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Net.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Numerics.Vectors.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Numerics.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ObjectModel.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.DispatchProxy.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.Emit.ILGeneration.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.Emit.Lightweight.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.Emit.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.Extensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.Metadata.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.TypeExtensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Reflection.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Resources.Reader.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Resources.ResourceManager.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Resources.Writer.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.CompilerServices.Unsafe.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.CompilerServices.VisualC.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Extensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Handles.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.InteropServices.JavaScript.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.InteropServices.RuntimeInformation.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.InteropServices.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Intrinsics.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Loader.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Numerics.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Serialization.Formatters.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Serialization.Json.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Serialization.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Serialization.Xml.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.Serialization.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Runtime.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.AccessControl.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Claims.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.Algorithms.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.Cng.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.Csp.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.Encoding.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.OpenSsl.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.Primitives.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.X509Certificates.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Cryptography.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Principal.Windows.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.Principal.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.SecureString.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Security.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ServiceModel.Web.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ServiceProcess.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Text.Encoding.CodePages.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Text.Encoding.Extensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Text.Encoding.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Text.Encodings.Web.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Text.Json.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Text.RegularExpressions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Channels.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Overlapped.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Tasks.Dataflow.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Tasks.Extensions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Tasks.Parallel.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Tasks.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Thread.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.ThreadPool.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.Timer.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Threading.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Transactions.Local.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Transactions.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.ValueTuple.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Web.HttpUtility.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Web.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Windows.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.Linq.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.ReaderWriter.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.Serialization.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.XDocument.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.XPath.XDocument.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.XPath.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.XmlDocument.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.XmlSerializer.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.Xml.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/System.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/WindowsBase.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/mscorlib.dll |
|
||||
| /microsoft.netcore.app.ref/7.0.2/ref/net7.0/netstandard.dll |
|
||||
@@ -0,0 +1,15 @@
|
||||
import csharp
|
||||
|
||||
private string getPath(Assembly a) {
|
||||
not a.getCompilation().getOutputAssembly() = a and
|
||||
exists(string s | s = a.getFile().getAbsolutePath() |
|
||||
result =
|
||||
s.substring(s.indexOf("GitHub/packages/") + "GitHub/packages/".length() + 16, s.length())
|
||||
or
|
||||
result = s and
|
||||
not exists(s.indexOf("GitHub/packages/"))
|
||||
)
|
||||
}
|
||||
|
||||
from Assembly a
|
||||
select getPath(a)
|
||||
@@ -0,0 +1 @@
|
||||
var dummy = "dummy";
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "7.0.102"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create([], lang="csharp", extra_args=["--extractor-option=buildless=true", "--extractor-option=cil=false"])
|
||||
@@ -1,7 +1,3 @@
|
||||
| /avalara.avatax/21.10.0/lib/net20/Avalara.AvaTax.RestClient.net20.dll |
|
||||
| /avalara.avatax/21.10.0/lib/net45/Avalara.AvaTax.RestClient.net45.dll |
|
||||
| /avalara.avatax/21.10.0/lib/net461/Avalara.AvaTax.RestClient.net461.dll |
|
||||
| /avalara.avatax/21.10.0/lib/netstandard16/Avalara.AvaTax.netstandard11.dll |
|
||||
| /avalara.avatax/21.10.0/lib/netstandard20/Avalara.AvaTax.netstandard20.dll |
|
||||
| /microsoft.bcl.asyncinterfaces/6.0.0/lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll |
|
||||
| /microsoft.netcore.app.ref/3.1.0/ref/netcoreapp3.1/System.Runtime.InteropServices.WindowsRuntime.dll |
|
||||
@@ -212,4 +208,4 @@
|
||||
| /microsoft.windowsdesktop.app.ref/7.0.2/ref/net7.0/UIAutomationTypes.dll |
|
||||
| /microsoft.windowsdesktop.app.ref/7.0.2/ref/net7.0/WindowsBase.dll |
|
||||
| /microsoft.windowsdesktop.app.ref/7.0.2/ref/net7.0/WindowsFormsIntegration.dll |
|
||||
| /newtonsoft.json/12.0.1/lib/portable-net45+win8+wp8+wpa81/Newtonsoft.Json.dll |
|
||||
| /newtonsoft.json/12.0.1/lib/netstandard2.0/Newtonsoft.Json.dll |
|
||||
|
||||
@@ -123,11 +123,13 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: predicate does not contain any tuples.
|
||||
*
|
||||
* Gets the instance type of this type. For an unbound generic type, the instance type
|
||||
* is a constructed type created from the unbound type, with each of the supplied type
|
||||
* arguments being the corresponding type parameter.
|
||||
*/
|
||||
ConstructedType getInstanceType() {
|
||||
deprecated ConstructedType getInstanceType() {
|
||||
result = this.getAConstructedGeneric() and
|
||||
forall(TypeParameter tp, int i | tp = this.getTypeParameter(i) | tp = result.getTypeArgument(i))
|
||||
}
|
||||
@@ -277,7 +279,7 @@ class TypeParameterConstraints extends Element, @type_parameter_constraints {
|
||||
* ```
|
||||
*/
|
||||
class UnboundGenericStruct extends Struct, UnboundGenericType {
|
||||
override ConstructedStruct getInstanceType() {
|
||||
deprecated override ConstructedStruct getInstanceType() {
|
||||
result = UnboundGenericType.super.getInstanceType()
|
||||
}
|
||||
|
||||
@@ -300,7 +302,7 @@ class UnboundGenericStruct extends Struct, UnboundGenericType {
|
||||
* ```
|
||||
*/
|
||||
class UnboundGenericClass extends Class, UnboundGenericType {
|
||||
override ConstructedClass getInstanceType() {
|
||||
deprecated override ConstructedClass getInstanceType() {
|
||||
result = UnboundGenericType.super.getInstanceType()
|
||||
}
|
||||
|
||||
@@ -323,7 +325,7 @@ class UnboundGenericClass extends Class, UnboundGenericType {
|
||||
* ```
|
||||
*/
|
||||
class UnboundGenericInterface extends Interface, UnboundGenericType {
|
||||
override ConstructedInterface getInstanceType() {
|
||||
deprecated override ConstructedInterface getInstanceType() {
|
||||
result = UnboundGenericType.super.getInstanceType()
|
||||
}
|
||||
|
||||
@@ -347,7 +349,7 @@ class UnboundGenericInterface extends Interface, UnboundGenericType {
|
||||
* ```
|
||||
*/
|
||||
class UnboundGenericDelegateType extends DelegateType, UnboundGenericType {
|
||||
override ConstructedDelegateType getInstanceType() {
|
||||
deprecated override ConstructedDelegateType getInstanceType() {
|
||||
result = UnboundGenericType.super.getInstanceType()
|
||||
}
|
||||
|
||||
|
||||
@@ -87,28 +87,16 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import ExternalFlowExtensions as Extensions
|
||||
private import internal.AccessPathSyntax
|
||||
private import internal.DataFlowDispatch
|
||||
private import internal.DataFlowPrivate
|
||||
private import internal.DataFlowPublic
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.FlowSummaryImplSpecific
|
||||
import ExternalFlowExtensions
|
||||
private import AccessPathSyntax
|
||||
private import DataFlowDispatch
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowPublic
|
||||
private import FlowSummaryImpl::Public
|
||||
private import FlowSummaryImpl::Private::External
|
||||
private import FlowSummaryImplSpecific
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate sourceModel = Extensions::sourceModel/9;
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate sinkModel = Extensions::sinkModel/9;
|
||||
|
||||
/** Holds if a summary model exists for the given parameters. */
|
||||
predicate summaryModel = Extensions::summaryModel/10;
|
||||
|
||||
/** Holds if a neutral model exists for the given parameters. */
|
||||
predicate neutralModel = Extensions::neutralModel/6;
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _) or
|
||||
@@ -310,10 +298,17 @@ class UnboundCallable extends Callable {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate hasName(Declaration d, string name) {
|
||||
d.(Operator).getFunctionName() = name
|
||||
or
|
||||
not d instanceof Operator and
|
||||
d.hasName(name)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate callableSpecInfo(Callable c, string namespace, string type, string name) {
|
||||
c.getDeclaringType().hasQualifiedName(namespace, type) and
|
||||
c.getName() = name
|
||||
hasName(c, name)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -326,7 +321,7 @@ private predicate subtypeSpecCandidate(string name, UnboundValueOrRefType t) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate callableInfo(Callable c, string name, UnboundValueOrRefType decl) {
|
||||
name = c.getName() and
|
||||
hasName(c, name) and
|
||||
decl = c.getDeclaringType()
|
||||
}
|
||||
|
||||
@@ -387,7 +382,7 @@ private Element interpretElement0(
|
||||
subtypes = true and result.(UnboundCallable).overridesOrImplementsUnbound(m)
|
||||
) and
|
||||
m.getDeclaringType() = t and
|
||||
m.hasName(name)
|
||||
hasName(m, name)
|
||||
|
|
||||
signature = ""
|
||||
or
|
||||
@@ -12,7 +12,7 @@ private import DataFlowImplCommon
|
||||
private import FlowSummaryImpl::Private
|
||||
private import FlowSummaryImpl::Public
|
||||
private import semmle.code.csharp.Unification
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
module HardcodedSymmetricEncryptionKey {
|
||||
private import semmle.code.csharp.frameworks.system.security.cryptography.SymmetricAlgorithm
|
||||
|
||||
@@ -7,7 +7,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.Local
|
||||
private import semmle.code.csharp.frameworks.system.codedom.Compiler
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* A data flow source for user input treated as code vulnerabilities.
|
||||
|
||||
@@ -6,7 +6,7 @@ import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
private import semmle.code.csharp.frameworks.system.Diagnostics
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* A source specific to command injection vulnerabilities.
|
||||
|
||||
@@ -8,7 +8,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
private import semmle.code.csharp.frameworks.system.DirectoryServices
|
||||
private import semmle.code.csharp.frameworks.system.directoryservices.Protocols
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* A data flow source for unvalidated user input that is used to construct LDAP queries.
|
||||
|
||||
@@ -8,7 +8,7 @@ private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.text.RegularExpressions
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* A data flow source for untrusted user input used in log entries.
|
||||
|
||||
@@ -7,7 +7,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.Local
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* A source specific to SQL injection vulnerabilities.
|
||||
|
||||
@@ -9,7 +9,7 @@ private import semmle.code.csharp.frameworks.system.Web
|
||||
private import semmle.code.csharp.frameworks.system.web.Mvc
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
private import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* A data flow source for unvalidated URL redirect vulnerabilities.
|
||||
|
||||
@@ -9,7 +9,7 @@ private import semmle.code.csharp.frameworks.system.Web
|
||||
private import semmle.code.csharp.frameworks.system.web.UI
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.Html
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.Remote
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.frameworks.ServiceStack::XSS
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ private import Remote
|
||||
private import semmle.code.csharp.commons.Loggers
|
||||
private import semmle.code.csharp.frameworks.system.Web
|
||||
private import semmle.code.csharp.frameworks.system.IO
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/**
|
||||
* An external location sink.
|
||||
|
||||
@@ -13,7 +13,7 @@ private import semmle.code.csharp.frameworks.system.web.UI
|
||||
private import semmle.code.csharp.frameworks.system.web.ui.WebControls
|
||||
private import semmle.code.csharp.frameworks.system.windows.Forms
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.asp.AspNet
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.windows.Forms
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/** A data flow source of local data. */
|
||||
abstract class LocalFlowSource extends DataFlow::Node {
|
||||
|
||||
@@ -12,7 +12,7 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls
|
||||
private import semmle.code.csharp.frameworks.WCF
|
||||
private import semmle.code.csharp.frameworks.microsoft.Owin
|
||||
private import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
/** A data flow source of remote user input. */
|
||||
abstract class RemoteFlowSource extends DataFlow::Node {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.frameworks.system.data.Common
|
||||
private import semmle.code.csharp.frameworks.system.data.Entity
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
from string namespaceAndType, int rows
|
||||
where
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
private import csharp
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
from string namespace, int pkgs, string kind, string part, int n
|
||||
where modelCoverage(namespace, pkgs, kind, part, n)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
from string package, string type, string name, string signature, string kind, string provenance
|
||||
where
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
from
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
from
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
from
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.frameworks.Test
|
||||
private import ModelEditor
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ private import semmle.code.csharp.commons.Util as Util
|
||||
private import semmle.code.csharp.commons.Collections as Collections
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
|
||||
@@ -26,7 +26,11 @@ private module FlowTestImpl implements InputSig<CsharpDataFlow> {
|
||||
}
|
||||
|
||||
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
|
||||
(if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and
|
||||
(
|
||||
result = getSourceArgString(src)
|
||||
or
|
||||
not exists(getSourceArgString(src)) and result = "line:" + src.getLocation().getStartLine()
|
||||
) and
|
||||
exists(sink)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import Taint::PathGraph
|
||||
import ModelValidation
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
import DataFlow
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import ModelValidation
|
||||
|
||||
from DataFlow::Node node, string kind
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
import DataFlow
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import ModelValidation
|
||||
|
||||
from DataFlow::Node node, string kind
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
import DataFlow
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import ModelValidation
|
||||
import semmle.code.csharp.dataflow.FlowSummary
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.AccessPathSyntax
|
||||
import ModelValidation
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
import shared.FlowSummaries
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable instanceof SummarizedCallable
|
||||
{
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/Newtonsoft.Json/13.0.3/Newtonsoft.Json.csproj
|
||||
semmle-extractor-options: --load-sources-from-project:../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/Dapper/2.0.90/Dapper.csproj
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/ServiceStack/6.2.0/ServiceStack.csproj
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/ServiceStack.OrmLite.SqlServer/6.2.0/ServiceStack.OrmLite.SqlServer.csproj
|
||||
semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs
|
||||
semmle-extractor-options: ${testdir}/../../../resources/stubs/EntityFramework.cs
|
||||
|
||||
@@ -13,7 +13,7 @@ class Types
|
||||
|
||||
class D : B<string>
|
||||
{
|
||||
public override void M() => Sink(this);
|
||||
public override void M() => Sink(this); // $ hasValueFlow=line:32 $ hasValueFlow=line:33 $ hasValueFlow=line:40
|
||||
}
|
||||
|
||||
static void M1()
|
||||
@@ -41,13 +41,13 @@ class Types
|
||||
M9(new D()); // no flow
|
||||
|
||||
object o = null; // flow
|
||||
Sink(o);
|
||||
Sink(o); // $ hasValueFlow=line:43
|
||||
}
|
||||
|
||||
static void M2(A a)
|
||||
{
|
||||
if (a is C c)
|
||||
Sink(c);
|
||||
Sink(c); // $ hasValueFlow=line:23
|
||||
}
|
||||
|
||||
static void M3(A a)
|
||||
@@ -55,18 +55,18 @@ class Types
|
||||
switch (a)
|
||||
{
|
||||
case D d:
|
||||
Sink(d);
|
||||
Sink(d); // $ hasValueFlow=line:35
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void M4(A a) => Sink((C)a);
|
||||
static void M4(A a) => Sink((C)a); // $ hasValueFlow=line:25
|
||||
|
||||
static void M5<T>(T x) => Sink(x);
|
||||
static void M5<T>(T x) => Sink(x); // $ hasValueFlow=line:26 $ hasValueFlow=line:37
|
||||
|
||||
static void M6<T>(T x) where T : A => Sink(x);
|
||||
static void M6<T>(T x) where T : A => Sink(x); // $ hasValueFlow=line:27 $ hasValueFlow=line:38
|
||||
|
||||
static void M7<T>(T x) where T : class => Sink(x);
|
||||
static void M7<T>(T x) where T : class => Sink(x); // $ hasValueFlow=line:28 $ hasValueFlow=line:39
|
||||
|
||||
static void M8<T>(T x)
|
||||
{
|
||||
@@ -77,7 +77,7 @@ class Types
|
||||
static void M9(A a)
|
||||
{
|
||||
if (a is B<int> b)
|
||||
Sink(b);
|
||||
Sink(b); // $ hasValueFlow=line:30
|
||||
}
|
||||
|
||||
static void Sink<T>(T x) { }
|
||||
@@ -112,15 +112,15 @@ class Types
|
||||
|
||||
public override void M()
|
||||
{
|
||||
Sink(this.Field);
|
||||
Sink(this.Field); // $ hasValueFlow=line:110
|
||||
}
|
||||
|
||||
void M10()
|
||||
{
|
||||
var a = new A();
|
||||
var e2 = new E2();
|
||||
Sink(Through(a)); // flow
|
||||
Sink(Through(e2)); // flow
|
||||
Sink(Through(a)); // $ hasValueFlow=line:120
|
||||
Sink(Through(e2)); // $ hasValueFlow=line:121
|
||||
Sink((E2)Through(a)); // no flow
|
||||
Sink((A)Through(e2)); // no flow
|
||||
}
|
||||
@@ -150,6 +150,28 @@ class Types
|
||||
|
||||
class FieldC : FieldA
|
||||
{
|
||||
public override void M() => Sink(this.Field);
|
||||
public override void M() => Sink(this.Field); // $ hasValueFlow=line:144
|
||||
}
|
||||
|
||||
class F
|
||||
{
|
||||
public virtual void M() { }
|
||||
|
||||
class F1<T> : F
|
||||
{
|
||||
public override void M() => Sink(this); // $ hasValueFlow=line:167
|
||||
}
|
||||
|
||||
class F2 : F { }
|
||||
|
||||
F GetF1() => new F1<int>();
|
||||
|
||||
F GetF2() => new F2();
|
||||
|
||||
private void M2()
|
||||
{
|
||||
GetF1().M();
|
||||
GetF2().M();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
testFailures
|
||||
edges
|
||||
| Types.cs:7:21:7:25 | this : D | Types.cs:7:32:7:35 | this access : D |
|
||||
| Types.cs:7:32:7:35 | this access : D | Types.cs:16:30:16:30 | this : D |
|
||||
@@ -54,6 +55,9 @@ edges
|
||||
| Types.cs:145:13:145:13 | access to parameter c : FieldC [field Field] : Object | Types.cs:138:21:138:25 | this : FieldC [field Field] : Object |
|
||||
| Types.cs:153:30:153:30 | this : FieldC [field Field] : Object | Types.cs:153:42:153:45 | this access : FieldC [field Field] : Object |
|
||||
| Types.cs:153:42:153:45 | this access : FieldC [field Field] : Object | Types.cs:153:42:153:51 | access to field Field |
|
||||
| Types.cs:162:34:162:34 | this : Types+F+F1<Int32> | Types.cs:162:46:162:49 | this access |
|
||||
| Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | Types.cs:173:13:173:19 | call to method GetF1 : Types+F+F1<Int32> |
|
||||
| Types.cs:173:13:173:19 | call to method GetF1 : Types+F+F1<Int32> | Types.cs:162:34:162:34 | this : Types+F+F1<Int32> |
|
||||
nodes
|
||||
| Types.cs:7:21:7:25 | this : D | semmle.label | this : D |
|
||||
| Types.cs:7:32:7:35 | this access : D | semmle.label | this access : D |
|
||||
@@ -123,6 +127,10 @@ nodes
|
||||
| Types.cs:153:30:153:30 | this : FieldC [field Field] : Object | semmle.label | this : FieldC [field Field] : Object |
|
||||
| Types.cs:153:42:153:45 | this access : FieldC [field Field] : Object | semmle.label | this access : FieldC [field Field] : Object |
|
||||
| Types.cs:153:42:153:51 | access to field Field | semmle.label | access to field Field |
|
||||
| Types.cs:162:34:162:34 | this : Types+F+F1<Int32> | semmle.label | this : Types+F+F1<Int32> |
|
||||
| Types.cs:162:46:162:49 | this access | semmle.label | this access |
|
||||
| Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | semmle.label | object creation of type F1<Int32> : Types+F+F1<Int32> |
|
||||
| Types.cs:173:13:173:19 | call to method GetF1 : Types+F+F1<Int32> | semmle.label | call to method GetF1 : Types+F+F1<Int32> |
|
||||
subpaths
|
||||
| Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:130:34:130:34 | x : A | Types.cs:130:40:130:40 | access to parameter x : A | Types.cs:122:22:122:31 | call to method Through |
|
||||
| Types.cs:123:30:123:31 | access to local variable e2 : Types+E<D>.E2 | Types.cs:130:34:130:34 | x : Types+E<D>.E2 | Types.cs:130:40:130:40 | access to parameter x : Types+E<D>.E2 | Types.cs:123:22:123:32 | call to method Through |
|
||||
@@ -145,3 +153,4 @@ subpaths
|
||||
| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through |
|
||||
| Types.cs:121:26:121:33 | object creation of type E2 : Types+E<D>.E2 | Types.cs:121:26:121:33 | object creation of type E2 : Types+E<D>.E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through |
|
||||
| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:153:42:153:51 | access to field Field | $@ | Types.cs:153:42:153:51 | access to field Field | access to field Field |
|
||||
| Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | Types.cs:162:46:162:49 | this access | $@ | Types.cs:162:46:162:49 | this access | this access |
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import Types::PathGraph
|
||||
import TestUtilities.InlineFlowTest
|
||||
import PathGraph
|
||||
|
||||
module TypesConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
@@ -17,10 +18,12 @@ module TypesConfig implements DataFlow::ConfigSig {
|
||||
mc.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = 1000 }
|
||||
}
|
||||
|
||||
module Types = DataFlow::Global<TypesConfig>;
|
||||
import ValueFlowTest<TypesConfig>
|
||||
|
||||
from Types::PathNode source, Types::PathNode sink
|
||||
where Types::flowPath(source, sink)
|
||||
from PathNode source, PathNode sink
|
||||
where flowPath(source, sink)
|
||||
select source, source, sink, "$@", sink, sink.toString()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import semmle.code.csharp.frameworks.EntityFramework::EntityFramework
|
||||
import shared.FlowSummaries
|
||||
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
|
||||
|
||||
private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable instanceof EFSummarizedCallable
|
||||
{ }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import semmle.code.csharp.frameworks.Sql
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPublic
|
||||
|
||||
query predicate sqlExpressions(SqlExpr se, Expr e) { se.getSql() = e }
|
||||
|
||||
@@ -80,16 +80,15 @@ function RegisterExtractorPack(id)
|
||||
end
|
||||
end
|
||||
|
||||
-- for `dotnet test`, we should not append `-p:UseSharedCompilation=false` to the command line
|
||||
-- if an `exe` or `dll` is passed as an argument as the call is forwarded to vstest.
|
||||
if testMatch and (arg:match('%.exe$') or arg:match('%.dll')) then
|
||||
match = false
|
||||
break
|
||||
end
|
||||
|
||||
-- we have found a sub-command, ignore all strings that look like sub-command names from now on
|
||||
inSubCommandPosition = false
|
||||
end
|
||||
-- for `dotnet test`, we should not append `-p:UseSharedCompilation=false` to the command line
|
||||
-- if an `exe` or `dll` is passed as an argument as the call is forwarded to vstest.
|
||||
if testMatch and (arg:match('%.exe$') or arg:match('%.dll')) then
|
||||
match = false
|
||||
break
|
||||
end
|
||||
-- if we see a separator to `dotnet run`, inject just prior to the existing separator
|
||||
if arg == '--' then
|
||||
dotnetRunNeedsSeparator = false
|
||||
|
||||
@@ -39,7 +39,7 @@ Changing the labels of query history items
|
||||
|
||||
The query history **Format** setting controls how the extension lists queries in the query history. By default, each item has a label with the following format::
|
||||
|
||||
%q on %d - %s, %r result count [%t]
|
||||
%q on %d - %s %r [%t]
|
||||
|
||||
- ``%q`` is the query name
|
||||
- ``%d`` is the database name
|
||||
@@ -107,6 +107,19 @@ You can also edit the items shown in the Variant Analysis Repositories panel by
|
||||
|
||||
You can change the items shown in the panel or add new items by directly editing this file.
|
||||
|
||||
Configuring settings for adding databases
|
||||
------------------------------------------------
|
||||
|
||||
To automatically add database source folders to your workspace, you can enable the **Adding Databases > Add Database Source to Workspace** setting.
|
||||
|
||||
This setting is disabled by default. You may want to enable the setting if you regularly browse the source code of databases, for example to view the abstract syntax tree of the code. For more information, see ":ref:`Exploring the structure of your source code <exploring-the-structure-of-your-source-code>`."
|
||||
|
||||
.. pull-quote:: Note
|
||||
|
||||
If you are in a single-folder workspace, adding database source folders will cause the workspace to reload as a multi-root workspace. This may cause query history and database lists to be reset.
|
||||
|
||||
Before enabling this setting, we recommend that you save your workspace as a multi-root workspace. For more information, see "`Multi-root Workspaces <https://code.visualstudio.com/docs/editor/multi-root-workspaces>`__" in the Visual Studio Code help.
|
||||
|
||||
Configuring settings for testing queries locally
|
||||
------------------------------------------------
|
||||
|
||||
|
||||
@@ -18,20 +18,26 @@ CodeQL for Visual Studio Code contains an AST viewer. The viewer consists of a g
|
||||
Viewing the abstract syntax tree of a source file
|
||||
--------------------------------------------------
|
||||
|
||||
1. Open a source file from a CodeQL database. For example, you can navigate to a source file in the File Explorer.
|
||||
1. Open the CodeQL Databases view and right-click the database that you want to explore. Click **Add Database Source to Workspace**.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/add-database-source-to-workspace.png
|
||||
:width: 350
|
||||
:alt: Add database source to workspace
|
||||
|
||||
2. Navigate to a CodeQL database's source file in the File Explorer.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/open-source-file.png
|
||||
:width: 350
|
||||
:alt: Open a source file
|
||||
|
||||
2. Run **CodeQL: View AST** from the Command Palette. This runs a CodeQL query (usually called ``printAST.ql``) over the active file, which may take a few seconds.
|
||||
3. Run **CodeQL: View AST** from the Command Palette. This runs a CodeQL query (usually called ``printAST.ql``) over the active file, which may take a few seconds.
|
||||
|
||||
.. pull-quote:: Note
|
||||
|
||||
If you don't have an appropriate ``printAST.ql`` query in your workspace, the **CodeQL: View AST** command won't work. To fix this, you can update your copy of the `CodeQL <https://github.com/github/codeql>`__ repository from ``main``. If you do this, you may need to upgrade your databases. Also, query caches may be discarded and your next query runs could be slower.
|
||||
|
||||
3. Once the query has run, the AST viewer displays the structure of the source file.
|
||||
4. To see the nested structure, click the arrows and expand the nodes.
|
||||
4. Once the query has run, the AST viewer displays the structure of the source file.
|
||||
5. To see the nested structure, click the arrows and expand the nodes.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/explore-ast.png
|
||||
:alt: Explore the AST
|
||||
|
||||
@@ -22,7 +22,7 @@ About extensible predicates
|
||||
|
||||
At a high level, there are two main components to using data extensions. The query writer defines one or more extensible predicates in their query libraries. CLI and code scanning users who want to augment these predicates supply one or more extension files whose data gets injected into the extensible predicate during evaluation. The extension files are either stored directly in the repository where the codebase to be analyzed is hosted, or downloaded as CodeQL model packs.
|
||||
|
||||
This example of an extensible predicate for a source is taken from the core Java libraries https://github.com/github/codeql/blob/main/java/ql/lib/semmle/code/java/dataflow/ExternalFlowExtensions.qll#L8-L11
|
||||
This example of an extensible predicate for a source is taken from the core Java libraries https://github.com/github/codeql/blob/main/java/ql/lib/semmle/code/java/dataflow/internal/ExternalFlowExtensions.qll#L8-L11
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 80 KiB |
@@ -11,8 +11,8 @@ and the CodeQL library pack ``codeql/cpp-all`` (`changelog <https://github.com/g
|
||||
:widths: auto
|
||||
|
||||
Name, Category
|
||||
`Bloomberg Standard Library <https://github.com/bloomberg/bde>`__, Utility library
|
||||
`Berkeley socket API library <https://en.wikipedia.org/wiki/Berkeley_sockets#Socket_API_functions>`__, Network communicator
|
||||
`Bloomberg Standard Library <https://github.com/bloomberg/bde>`__, Utility library
|
||||
string.h, String library
|
||||
|
||||
C# built-in support
|
||||
@@ -82,8 +82,8 @@ and the CodeQL library pack ``codeql/go-all`` (`changelog <https://github.com/gi
|
||||
`nhooyr.io/websocket <http://nhooyr.io/websocket>`_, Network communicator
|
||||
`protobuf <https://pkg.go.dev/google.golang.org/protobuf>`_, Serialization
|
||||
`Revel <http://revel.github.io/>`_, Web framework
|
||||
`sqlx <http://jmoiron.github.io/sqlx/>`_, Database
|
||||
`SendGrid <https://github.com/sendgrid/sendgrid-go>`_, Email library
|
||||
`sqlx <http://jmoiron.github.io/sqlx/>`_, Database
|
||||
`Squirrel <https://github.com/Masterminds/squirrel>`_, Database
|
||||
`ws <https://github.com/gobwas/ws>`_, Network communicator
|
||||
`xmlpath <https://gopkg.in/xmlpath.v2>`_, XPath library
|
||||
@@ -108,20 +108,20 @@ and the CodeQL library pack ``codeql/java-all`` (`changelog <https://github.com/
|
||||
:widths: auto
|
||||
|
||||
Name, Category
|
||||
Apache Commons Lang, Utility library
|
||||
Apache Commons Collections, Data structure utility library
|
||||
Apache Commons Lang, Utility library
|
||||
Apache HTTP components, Network communicator
|
||||
Guava, Utility and collections library
|
||||
Hibernate, Database
|
||||
iBatis / MyBatis, Database
|
||||
Jackson, Serialization
|
||||
JSON-java, Serialization
|
||||
Java Persistence API (JPA), Database
|
||||
JaxRS, Jakarta EE API specification
|
||||
JDBC, Database
|
||||
Protobuf, Serialization
|
||||
JSON-java, Serialization
|
||||
Kryo deserialization, Serialization
|
||||
Project Lombok, Utility library
|
||||
Protobuf, Serialization
|
||||
SnakeYaml, Serialization
|
||||
Spring JDBC, Database
|
||||
Spring MVC, Web application framework
|
||||
@@ -160,8 +160,8 @@ and the CodeQL library pack ``codeql/javascript-all`` (`changelog <https://githu
|
||||
mssql, Database
|
||||
mustache, templating language
|
||||
mysql, Database
|
||||
node, Runtime environment
|
||||
nest.js, Server
|
||||
node, Runtime environment
|
||||
nunjucks, templating language
|
||||
postgres, Database
|
||||
ramda, Utility library
|
||||
@@ -197,12 +197,12 @@ and the CodeQL library pack ``codeql/python-all`` (`changelog <https://github.co
|
||||
djangorestframework, Web framework
|
||||
FastAPI, Web framework
|
||||
Flask, Web framework
|
||||
Flask-Admin, Web framework
|
||||
Tornado, Web framework
|
||||
Twisted, Web framework
|
||||
Flask-Admin, Web framework
|
||||
starlette, Asynchronous Server Gateway Interface (ASGI)
|
||||
python-ldap, Lightweight Directory Access Protocol (LDAP)
|
||||
ldap3, Lightweight Directory Access Protocol (LDAP)
|
||||
python-ldap, Lightweight Directory Access Protocol (LDAP)
|
||||
httpx, HTTP client
|
||||
pycurl, HTTP client
|
||||
requests, HTTP client
|
||||
@@ -230,8 +230,8 @@ and the CodeQL library pack ``codeql/python-all`` (`changelog <https://github.co
|
||||
cassandra-driver, Database
|
||||
clickhouse-driver, Database
|
||||
cx_Oracle, Database
|
||||
mysql-connector-python, Database
|
||||
mysql-connector, Database
|
||||
mysql-connector-python, Database
|
||||
MySQL-python, Database
|
||||
mysqlclient, Database
|
||||
oracledb, Database
|
||||
@@ -310,5 +310,5 @@ and the CodeQL library pack ``codeql/swift-all`` (`changelog <https://github.com
|
||||
`RNCryptor <https://github.com/RNCryptor/RNCryptor>`__, Cryptography library
|
||||
`SQLite3 <https://sqlite.org/index.html>`__, Database
|
||||
`SQLite.swift <https://github.com/stephencelis/SQLite.swift>`__, Database
|
||||
`WebKit <https://developer.apple.com/documentation/webkit>`__, User interface library
|
||||
`UIKit <https://developer.apple.com/documentation/uikit>`__, User interface library
|
||||
`WebKit <https://developer.apple.com/documentation/webkit>`__, User interface library
|
||||
|
||||
@@ -47,7 +47,7 @@ endif
|
||||
qhelp-to-markdown:
|
||||
scripts/qhelp-to-markdown.sh ql/src "$(QHELP_OUT_DIR)"
|
||||
|
||||
tools: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))) tools/tokenizer.jar
|
||||
tools: tools-codeql tools/tokenizer.jar
|
||||
|
||||
.PHONY: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES)))
|
||||
$(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))):
|
||||
@@ -67,7 +67,10 @@ tools-osx64: $(addprefix tools/osx64/,$(BINARIES))
|
||||
|
||||
.PHONY: $(addprefix tools/osx64/,$(BINARIES))
|
||||
$(addprefix tools/osx64/,$(BINARIES)):
|
||||
GOOS=darwin GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(@F)
|
||||
GOOS=darwin GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@.amd64 ./cli/$(@F)
|
||||
GOOS=darwin GOARCH=arm64 go build -C extractor -mod=vendor -o ../$@.arm64 ./cli/$(@F)
|
||||
lipo -create $@.amd64 $@.arm64 -output $@
|
||||
rm $@.amd64 $@.arm64
|
||||
|
||||
tools-win64: $(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES)))
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ module github.com/github/codeql-go/extractor
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.13.0
|
||||
golang.org/x/tools v0.14.0
|
||||
golang.org/x/mod v0.14.0
|
||||
golang.org/x/tools v0.15.0
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.13.0 // indirect
|
||||
require golang.org/x/sys v0.14.0 // indirect
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user