mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Merge branch 'main' into criemen/js-bazel
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))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
@@ -332,10 +225,7 @@ module SemanticExprConfig {
|
||||
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()
|
||||
|
|
||||
exists(IR::Operand operand | operand.getDef() = v.asInstruction() |
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
)
|
||||
@@ -353,10 +243,7 @@ module SemanticExprConfig {
|
||||
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()
|
||||
|
|
||||
exists(IR::PhiInputOperand operand | operand.getDef() = v.asInstruction() |
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
@@ -433,7 +320,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) }
|
||||
|
||||
@@ -63,36 +63,3 @@ class SemSsaReadPositionBlock extends SemSsaReadPosition {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -72,14 +72,12 @@ module Sem implements Semantic {
|
||||
|
||||
class BasicBlock = SemBasicBlock;
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class Guard = SemGuard;
|
||||
|
||||
predicate implies_v2 = semImplies_v2/4;
|
||||
|
||||
predicate guardDirectlyControlsSsaRead = semGuardDirectlyControlsSsaRead/3;
|
||||
|
||||
predicate guardControlsSsaRead = semGuardControlsSsaRead/3;
|
||||
|
||||
class Type = SemType;
|
||||
|
||||
class IntegerType = SemIntegerType;
|
||||
@@ -100,8 +98,6 @@ module Sem implements Semantic {
|
||||
|
||||
class SsaReadPositionBlock = SemSsaReadPositionBlock;
|
||||
|
||||
predicate backEdge = semBackEdge/3;
|
||||
|
||||
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
||||
SemanticType::conversionCannotOverflow(fromType, toType)
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
) {
|
||||
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
|
||||
@@ -318,7 +318,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
) {
|
||||
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
|
||||
@@ -343,7 +343,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition 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
|
||||
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -82,8 +82,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
? new[] { options.SolutionFile }
|
||||
: allNonBinaryFiles.SelectFileNamesByExtension(".sln");
|
||||
var dllPaths = options.DllDirs.Count == 0
|
||||
? allFiles.SelectFileNamesByExtension(".dll").ToList()
|
||||
: options.DllDirs.Select(Path.GetFullPath).ToList();
|
||||
? allFiles.SelectFileNamesByExtension(".dll").ToHashSet()
|
||||
: options.DllDirs.Select(Path.GetFullPath).ToHashSet();
|
||||
|
||||
if (options.UseNuGet)
|
||||
{
|
||||
@@ -107,7 +107,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
.RequiredPaths
|
||||
.Select(d => Path.Combine(packageDirectory.DirInfo.FullName, d))
|
||||
.ToList();
|
||||
dllPaths.AddRange(paths);
|
||||
dllPaths.UnionWith(paths);
|
||||
|
||||
LogAllUnusedPackages(dependencies);
|
||||
DownloadMissingPackages(allNonBinaryFiles, dllPaths);
|
||||
@@ -205,7 +205,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
private void AddNetFrameworkDlls(List<string> dllPaths)
|
||||
private void AddNetFrameworkDlls(ISet<string> dllPaths)
|
||||
{
|
||||
// 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.
|
||||
@@ -218,13 +218,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
};
|
||||
|
||||
var frameworkPath = packagesInPrioOrder
|
||||
.Select(GetPackageDirectory)
|
||||
.FirstOrDefault(dir => dir is not null);
|
||||
.Select((s, index) => (Index: index, Path: GetPackageDirectory(s)))
|
||||
.FirstOrDefault(pair => pair.Path is not null);
|
||||
|
||||
if (frameworkPath is not null)
|
||||
if (frameworkPath.Path is not null)
|
||||
{
|
||||
dllPaths.Add(frameworkPath);
|
||||
progressMonitor.LogInfo("Found .NET Core/Framework DLLs in NuGet packages. Not adding installation directory.");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -249,7 +255,29 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
dllPaths.Add(runtimeLocation);
|
||||
}
|
||||
|
||||
private void AddAspNetCoreFrameworkDlls(List<string> dllPaths)
|
||||
private void RemoveNugetPackageReference(string packagePrefix, ISet<string> dllPaths)
|
||||
{
|
||||
if (!options.UseNuGet)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
|
||||
if (packageFolder == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
|
||||
var toRemove = dllPaths.Where(s => s.ToLowerInvariant().StartsWith(packagePathPrefix));
|
||||
foreach (var path in toRemove)
|
||||
{
|
||||
dllPaths.Remove(path);
|
||||
progressMonitor.RemovedReference(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths)
|
||||
{
|
||||
if (!fileContent.IsNewProjectStructureUsed || !fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
@@ -269,7 +297,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
private void AddMicrosoftWindowsDesktopDlls(List<string> dllPaths)
|
||||
private void AddMicrosoftWindowsDesktopDlls(ISet<string> dllPaths)
|
||||
{
|
||||
if (GetPackageDirectory("microsoft.windowsdesktop.app.ref") is string windowsDesktopApp)
|
||||
{
|
||||
@@ -628,7 +656,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
assets = assetFiles;
|
||||
}
|
||||
|
||||
private void DownloadMissingPackages(List<FileInfo> allFiles, List<string> dllPaths)
|
||||
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths)
|
||||
{
|
||||
var nugetConfigs = allFiles.SelectFileNamesByName("nuget.config").ToArray();
|
||||
string? nugetConfig = null;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
@@ -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"])
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
@@ -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)))
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
*/
|
||||
|
||||
private import go
|
||||
private import ExternalFlowExtensions as Extensions
|
||||
import internal.ExternalFlowExtensions
|
||||
private import internal.DataFlowPrivate
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.FlowSummaryImplSpecific
|
||||
@@ -82,15 +82,6 @@ private import internal.AccessPathSyntax
|
||||
private import FlowSummary
|
||||
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 `package` have MaD framework coverage. */
|
||||
private predicate packageHasMaDCoverage(string package) {
|
||||
sourceModel(package, _, _, _, _, _, _, _, _) or
|
||||
|
||||
@@ -93,7 +93,7 @@ private import internal.DataFlowPrivate
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
||||
private import internal.AccessPathSyntax
|
||||
private import ExternalFlowExtensions as Extensions
|
||||
private import internal.ExternalFlowExtensions as Extensions
|
||||
private import FlowSummary
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
|
||||
|
||||
@@ -211,7 +211,11 @@ module Sem implements Semantic {
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
class Guard extends GL::Guard {
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
|
||||
|
||||
final private class FinalGuard = GL::Guard;
|
||||
|
||||
class Guard extends FinalGuard {
|
||||
Expr asExpr() { result = this }
|
||||
}
|
||||
|
||||
@@ -219,14 +223,6 @@ module Sem implements Semantic {
|
||||
GL::implies_v2(g1, b1, g2, b2)
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsSsaRead(Guard guard, SsaReadPosition controlled, boolean testIsTrue) {
|
||||
RU::guardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
|
||||
}
|
||||
|
||||
predicate guardControlsSsaRead(Guard guard, SsaReadPosition controlled, boolean testIsTrue) {
|
||||
RU::guardControlsSsaRead(guard, controlled, testIsTrue)
|
||||
}
|
||||
|
||||
class Type = J::Type;
|
||||
|
||||
class IntegerType extends J::IntegralType {
|
||||
@@ -261,6 +257,10 @@ module Sem implements Semantic {
|
||||
|
||||
class SsaReadPositionPhiInputEdge extends SsaReadPosition instanceof SsaReadPos::SsaReadPositionPhiInputEdge
|
||||
{
|
||||
BasicBlock getOrigBlock() { result = super.getOrigBlock() }
|
||||
|
||||
BasicBlock getPhiBlock() { result = super.getPhiBlock() }
|
||||
|
||||
predicate phiInput(SsaPhiNode phi, SsaVariable inp) { super.phiInput(phi, inp) }
|
||||
}
|
||||
|
||||
@@ -268,10 +268,6 @@ module Sem implements Semantic {
|
||||
BasicBlock getBlock() { result = super.getBlock() }
|
||||
}
|
||||
|
||||
predicate backEdge(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge) {
|
||||
RU::backEdge(phi, inp, edge)
|
||||
}
|
||||
|
||||
predicate conversionCannotOverflow = safeCast/2;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,18 @@ private import SSA
|
||||
private import semmle.code.java.controlflow.internal.GuardsLogic
|
||||
private import semmle.code.java.dataflow.internal.rangeanalysis.SsaReadPositionCommon
|
||||
private import semmle.code.java.Constants
|
||||
private import semmle.code.java.dataflow.RangeAnalysis
|
||||
private import codeql.rangeanalysis.internal.RangeUtils
|
||||
|
||||
private module U = MakeUtils<Sem, IntDelta>;
|
||||
|
||||
private predicate backEdge = U::backEdge/3;
|
||||
|
||||
predicate ssaRead = U::ssaRead/2;
|
||||
|
||||
predicate guardDirectlyControlsSsaRead = U::guardDirectlyControlsSsaRead/3;
|
||||
|
||||
predicate guardControlsSsaRead = U::guardControlsSsaRead/3;
|
||||
|
||||
/**
|
||||
* Holds if `v` is an input to `phi` that is not along a back edge, and the
|
||||
@@ -145,79 +157,6 @@ class ConstantStringExpr extends Expr {
|
||||
string getStringValue() { constantStringExpr(this, result) }
|
||||
}
|
||||
|
||||
bindingset[f]
|
||||
private predicate okInt(float f) { -2.pow(31) <= f and f <= 2.pow(31) - 1 }
|
||||
|
||||
/**
|
||||
* Gets an expression that equals `v - d`.
|
||||
*/
|
||||
Expr ssaRead(SsaVariable v, int delta) {
|
||||
result = v.getAUse() and delta = 0
|
||||
or
|
||||
exists(int d1, ConstantIntegerExpr c |
|
||||
result.(AddExpr).hasOperands(ssaRead(v, d1), c) and
|
||||
delta = d1 - c.getIntValue() and
|
||||
okInt(d1.(float) - c.getIntValue().(float))
|
||||
)
|
||||
or
|
||||
exists(SubExpr sub, int d1, ConstantIntegerExpr c |
|
||||
result = sub and
|
||||
sub.getLeftOperand() = ssaRead(v, d1) and
|
||||
sub.getRightOperand() = c and
|
||||
delta = d1 + c.getIntValue() and
|
||||
okInt(d1.(float) + c.getIntValue().(float))
|
||||
)
|
||||
or
|
||||
v.(SsaExplicitUpdate).getDefiningExpr().(PreIncExpr) = result and delta = 0
|
||||
or
|
||||
v.(SsaExplicitUpdate).getDefiningExpr().(PreDecExpr) = result and delta = 0
|
||||
or
|
||||
v.(SsaExplicitUpdate).getDefiningExpr().(PostIncExpr) = result and delta = 1 // x++ === ++x - 1
|
||||
or
|
||||
v.(SsaExplicitUpdate).getDefiningExpr().(PostDecExpr) = result and delta = -1 // x-- === --x + 1
|
||||
or
|
||||
v.(SsaExplicitUpdate).getDefiningExpr().(Assignment) = result and delta = 0
|
||||
or
|
||||
result.(AssignExpr).getSource() = ssaRead(v, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along a back edge.
|
||||
*/
|
||||
predicate backEdge(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge 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
|
||||
not hasDominanceInformation(edge.getOrigBlock())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` directly controls the position `controlled` with the
|
||||
* value `testIsTrue`.
|
||||
*/
|
||||
predicate guardDirectlyControlsSsaRead(Guard guard, SsaReadPosition controlled, boolean testIsTrue) {
|
||||
guard.directlyControls(controlled.(SsaReadPositionBlock).getBlock(), testIsTrue)
|
||||
or
|
||||
exists(SsaReadPositionPhiInputEdge 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 guardControlsSsaRead(Guard guard, SsaReadPosition controlled, boolean testIsTrue) {
|
||||
guardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
|
||||
or
|
||||
exists(Guard guard0, boolean testIsTrue0 |
|
||||
implies_v2(guard0, testIsTrue0, guard, testIsTrue) and
|
||||
guardControlsSsaRead(guard0, controlled, testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
||||
*
|
||||
|
||||
10
java/ql/lib/semmle/code/java/frameworks/Jms.qll
Normal file
10
java/ql/lib/semmle/code/java/frameworks/Jms.qll
Normal file
@@ -0,0 +1,10 @@
|
||||
/** Provides definitions for working with the JMS library. */
|
||||
|
||||
import java
|
||||
|
||||
/** The method `ObjectMessage.getObject`. */
|
||||
class ObjectMessageGetObjectMethod extends Method {
|
||||
ObjectMessageGetObjectMethod() {
|
||||
this.hasQualifiedName(["javax", "jakarta"] + ".jms", "ObjectMessage", "getObject")
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.TaintTracking2
|
||||
private import semmle.code.java.dispatch.VirtualDispatch
|
||||
private import semmle.code.java.frameworks.Kryo
|
||||
private import semmle.code.java.frameworks.XStream
|
||||
private import semmle.code.java.frameworks.SnakeYaml
|
||||
@@ -15,6 +16,7 @@ private import semmle.code.java.frameworks.HessianBurlap
|
||||
private import semmle.code.java.frameworks.Castor
|
||||
private import semmle.code.java.frameworks.Jackson
|
||||
private import semmle.code.java.frameworks.Jabsorb
|
||||
private import semmle.code.java.frameworks.Jms
|
||||
private import semmle.code.java.frameworks.JoddJson
|
||||
private import semmle.code.java.frameworks.Flexjson
|
||||
private import semmle.code.java.frameworks.google.Gson
|
||||
@@ -224,6 +226,11 @@ predicate unsafeDeserialization(MethodCall ma, Expr sink) {
|
||||
m instanceof GsonDeserializeMethod and
|
||||
sink = ma.getArgument(0) and
|
||||
UnsafeTypeFlow::flowToExpr(ma.getArgument(1))
|
||||
or
|
||||
m.getASourceOverriddenMethod*() instanceof ObjectMessageGetObjectMethod and
|
||||
sink = ma.getQualifier().getUnderlyingExpr() and
|
||||
// If we can see an implementation, we trust dataflow to find a path to the other sinks instead
|
||||
not exists(viableCallable(ma))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* James Kirrage, Asiri Rathnayake, Hayo Thielecke: Static Analysis for
|
||||
* Regular Expression Denial-of-Service Attacks. NSS 2013.
|
||||
* (http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf)
|
||||
* (https://arxiv.org/abs/1301.0849)
|
||||
* Asiri Rathnayake, Hayo Thielecke: Static Analysis for Regular Expression
|
||||
* Exponential Runtime via Substructural Logics. 2014.
|
||||
* (https://www.cs.bham.ac.uk/~hxt/research/redos_full.pdf)
|
||||
|
||||
@@ -15,7 +15,7 @@ may have unforeseen effects, such as the execution of arbitrary code.
|
||||
<p>
|
||||
There are many different serialization frameworks. This query currently
|
||||
supports Kryo, XmlDecoder, XStream, SnakeYaml, JYaml, JsonIO, YAMLBeans, HessianBurlap, Castor, Burlap,
|
||||
Jackson, Jabsorb, Jodd JSON, Flexjson, Gson and Java IO serialization through
|
||||
Jackson, Jabsorb, Jodd JSON, Flexjson, Gson, JMS, and Java IO serialization through
|
||||
<code>ObjectInputStream</code>/<code>ObjectOutputStream</code>.
|
||||
</p>
|
||||
</overview>
|
||||
@@ -74,6 +74,12 @@ Recommendations specific to particular frameworks supported by this query:
|
||||
<li><b>Recommendation</b>: Do not use with untrusted user input.</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
<p><b>ObjectMesssage</b> - <code>Java EE/Jakarta EE</code></p>
|
||||
<ul>
|
||||
<li><b>Secure by Default</b>: Depends on the JMS implementation.</li>
|
||||
<li><b>Recommendation</b>: Do not use with untrusted user input.</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
@@ -158,6 +164,10 @@ RCE in Flexjson:
|
||||
Android Intent deserialization vulnerabilities with GSON parser:
|
||||
<a href="https://blog.oversecured.com/Exploiting-memory-corruption-vulnerabilities-on-Android/#insecure-use-of-json-parsers">Insecure use of JSON parsers</a>.
|
||||
</li>
|
||||
<li>
|
||||
Research by Matthias Kaiser:
|
||||
<a href="https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf">Pwning Your Java Messaging With Deserialization Vulnerabilities</a>.
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/ReDoS">ReDoS</a>.</li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Time_complexity">Time complexity</a>.</li>
|
||||
<li>James Kirrage, Asiri Rathnayake, Hayo Thielecke:
|
||||
<a href="http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf">Static Analysis for Regular Expression Denial-of-Service Attack</a>.
|
||||
<a href="https://arxiv.org/abs/1301.0849">Static Analysis for Regular Expression Denial-of-Service Attack</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `java/unsafe-deserialization` has been improved to detect insecure calls to `ObjectMessage.getObject` in JMS.
|
||||
@@ -0,0 +1,9 @@
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageListener;
|
||||
import javax.jms.ObjectMessage;
|
||||
|
||||
public class ObjectMessageTest implements MessageListener {
|
||||
public void onMessage(Message message) {
|
||||
((ObjectMessage) message).getObject(); // $ unsafeDeserialization
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1:${testdir}/../../../stubs/gson-2.8.6:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/serialkiller-4.0.0
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1:${testdir}/../../../stubs/gson-2.8.6:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/serialkiller-4.0.0:${testdir}/../../../stubs/jms-api-1
|
||||
|
||||
@@ -892,10 +892,15 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
|
||||
// For named packages, find the main file.
|
||||
String name = packageJson.getName();
|
||||
if (name != null) {
|
||||
Path entryPoint = guessPackageMainFile(path, packageJson, FileType.TYPESCRIPT.getExtensions());
|
||||
if (entryPoint == null) {
|
||||
// Try a TypeScript-recognized JS extension instead
|
||||
entryPoint = guessPackageMainFile(path, packageJson, Arrays.asList(".js", ".jsx"));
|
||||
Path entryPoint = null;
|
||||
try {
|
||||
entryPoint = guessPackageMainFile(path, packageJson, FileType.TYPESCRIPT.getExtensions());
|
||||
if (entryPoint == null) {
|
||||
// Try a TypeScript-recognized JS extension instead
|
||||
entryPoint = guessPackageMainFile(path, packageJson, Arrays.asList(".js", ".jsx"));
|
||||
}
|
||||
} catch (InvalidPathException ignore) {
|
||||
// can happen if the `main:` field is invalid. E.g. on Windows a path like `dist/*.js` will crash.
|
||||
}
|
||||
if (entryPoint != null) {
|
||||
System.out.println(relativePath + ": Main file set to " + sourceRoot.relativize(entryPoint));
|
||||
|
||||
@@ -51,6 +51,7 @@ private module AsmCrypto {
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::PropRead algorithmSelection;
|
||||
private string algorithmName;
|
||||
private string methodName;
|
||||
|
||||
@@ -68,11 +69,14 @@ private module AsmCrypto {
|
||||
exists(DataFlow::SourceNode asmCrypto |
|
||||
asmCrypto = DataFlow::globalVarRef("asmCrypto") and
|
||||
algorithm.matchesName(algorithmName) and
|
||||
this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(methodName) and
|
||||
algorithmSelection = asmCrypto.getAPropertyRead(algorithmName) and
|
||||
this = algorithmSelection.getAMemberCall(methodName) and
|
||||
input = this.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = algorithmSelection }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -103,6 +107,7 @@ private module BrowserIdCrypto {
|
||||
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode {
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::CallNode keygen;
|
||||
|
||||
Apply() {
|
||||
/*
|
||||
@@ -122,8 +127,7 @@ private module BrowserIdCrypto {
|
||||
*/
|
||||
|
||||
exists(
|
||||
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::CallNode keygen,
|
||||
DataFlow::FunctionNode callback
|
||||
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::FunctionNode callback
|
||||
|
|
||||
mod = DataFlow::moduleImport("browserid-crypto") and
|
||||
keygen = mod.getAMemberCall("generateKeypair") and
|
||||
@@ -134,6 +138,8 @@ private module BrowserIdCrypto {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = keygen }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -239,6 +245,8 @@ private module NodeJSCrypto {
|
||||
|
||||
Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = instantiation }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() }
|
||||
@@ -324,7 +332,9 @@ private module CryptoJS {
|
||||
)
|
||||
}
|
||||
|
||||
private API::CallNode getEncryptionApplication(API::Node input, CryptographicAlgorithm algorithm) {
|
||||
private API::CallNode getEncryptionApplication(
|
||||
API::Node input, API::Node algorithmNode, CryptographicAlgorithm algorithm
|
||||
) {
|
||||
/*
|
||||
* ```
|
||||
* var CryptoJS = require("crypto-js");
|
||||
@@ -338,11 +348,14 @@ private module CryptoJS {
|
||||
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
|
||||
*/
|
||||
|
||||
result = getAlgorithmNode(algorithm).getMember("encrypt").getACall() and
|
||||
algorithmNode = getAlgorithmNode(algorithm) and
|
||||
result = algorithmNode.getMember("encrypt").getACall() and
|
||||
input = result.getParameter(0)
|
||||
}
|
||||
|
||||
private API::CallNode getDirectApplication(API::Node input, CryptographicAlgorithm algorithm) {
|
||||
private API::CallNode getDirectApplication(
|
||||
API::Node input, API::Node algorithmNode, CryptographicAlgorithm algorithm
|
||||
) {
|
||||
/*
|
||||
* ```
|
||||
* var CryptoJS = require("crypto-js");
|
||||
@@ -357,7 +370,8 @@ private module CryptoJS {
|
||||
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
|
||||
*/
|
||||
|
||||
result = getAlgorithmNode(algorithm).getACall() and
|
||||
algorithmNode = getAlgorithmNode(algorithm) and
|
||||
result = algorithmNode.getACall() and
|
||||
input = result.getParameter(0)
|
||||
}
|
||||
|
||||
@@ -389,18 +403,23 @@ private module CryptoJS {
|
||||
private class Apply extends CryptographicOperation::Range instanceof API::CallNode {
|
||||
API::Node input;
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::Node instantiation;
|
||||
|
||||
Apply() {
|
||||
this = getEncryptionApplication(input, algorithm)
|
||||
or
|
||||
this = getDirectApplication(input, algorithm)
|
||||
or
|
||||
exists(InstantiatedAlgorithm instantiation |
|
||||
this = getUpdatedApplication(input, instantiation) and
|
||||
algorithm = instantiation.getAlgorithm()
|
||||
exists(API::Node algorithmNode |
|
||||
this = getEncryptionApplication(input, algorithmNode, algorithm)
|
||||
or
|
||||
this = getDirectApplication(input, algorithmNode, algorithm)
|
||||
|
|
||||
instantiation = algorithmNode.asSource()
|
||||
)
|
||||
or
|
||||
this = getUpdatedApplication(input, instantiation) and
|
||||
algorithm = instantiation.(InstantiatedAlgorithm).getAlgorithm()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = instantiation }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input.asSink() }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -504,6 +523,8 @@ private module TweetNaCl {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -539,6 +560,7 @@ private module HashJs {
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::CallNode init;
|
||||
|
||||
Apply() {
|
||||
/*
|
||||
@@ -554,10 +576,13 @@ private module HashJs {
|
||||
* Also matches where `hash.<algorithmName>()` has been replaced by a more specific require a la `require("hash.js/lib/hash/sha/512")`
|
||||
*/
|
||||
|
||||
this = getAlgorithmNode(algorithm).getAMemberCall("update") and
|
||||
init = getAlgorithmNode(algorithm) and
|
||||
this = init.getAMemberCall("update") and
|
||||
input = super.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = init }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -653,6 +678,8 @@ private module Forge {
|
||||
algorithm = cipher.getAlgorithm()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = cipher }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -715,6 +742,8 @@ private module Md5 {
|
||||
super.getArgument(0) = input
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -731,17 +760,18 @@ private module Bcrypt {
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
CryptographicAlgorithm algorithm;
|
||||
API::Node init;
|
||||
|
||||
Apply() {
|
||||
// `require("bcrypt").hash(password);` with minor naming variations
|
||||
algorithm.matchesName("BCRYPT") and
|
||||
this =
|
||||
API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"])
|
||||
.getMember(["hash", "hashSync"])
|
||||
.getACall() and
|
||||
init = API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"]) and
|
||||
this = init.getMember(["hash", "hashSync"]).getACall() and
|
||||
super.getArgument(0) = input
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = init.asSource() }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -769,6 +799,8 @@ private module Hasha {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
|
||||
@@ -40,6 +40,9 @@ module Cryptography {
|
||||
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
|
||||
CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() }
|
||||
|
||||
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
DataFlow::Node getInitialization() { result = super.getInitialization() }
|
||||
|
||||
/** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */
|
||||
DataFlow::Node getAnInput() { result = super.getAnInput() }
|
||||
|
||||
@@ -65,6 +68,9 @@ module Cryptography {
|
||||
* extend `CryptographicOperation` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
abstract DataFlow::Node getInitialization();
|
||||
|
||||
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
|
||||
abstract CryptographicAlgorithm getAlgorithm();
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@ module BrokenCryptoAlgorithm {
|
||||
/**
|
||||
* A data flow sink for sensitive information in broken or weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
abstract DataFlow::Node getInitialization();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for sensitive information in broken or weak cryptographic algorithms.
|
||||
@@ -38,15 +41,17 @@ module BrokenCryptoAlgorithm {
|
||||
* An expression used by a broken or weak cryptographic algorithm.
|
||||
*/
|
||||
class WeakCryptographicOperationSink extends Sink {
|
||||
CryptographicOperation application;
|
||||
|
||||
WeakCryptographicOperationSink() {
|
||||
exists(CryptographicOperation application |
|
||||
(
|
||||
application.getAlgorithm().isWeak()
|
||||
or
|
||||
application.getBlockMode().isWeak()
|
||||
) and
|
||||
this = application.getAnInput()
|
||||
)
|
||||
(
|
||||
application.getAlgorithm().isWeak()
|
||||
or
|
||||
application.getBlockMode().isWeak()
|
||||
) and
|
||||
this = application.getAnInput()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = application.getInitialization() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* James Kirrage, Asiri Rathnayake, Hayo Thielecke: Static Analysis for
|
||||
* Regular Expression Denial-of-Service Attacks. NSS 2013.
|
||||
* (http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf)
|
||||
* (https://arxiv.org/abs/1301.0849)
|
||||
* Asiri Rathnayake, Hayo Thielecke: Static Analysis for Regular Expression
|
||||
* Exponential Runtime via Substructural Logics. 2014.
|
||||
* (https://www.cs.bham.ac.uk/~hxt/research/redos_full.pdf)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/ReDoS">ReDoS</a>.</li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Time_complexity">Time complexity</a>.</li>
|
||||
<li>James Kirrage, Asiri Rathnayake, Hayo Thielecke:
|
||||
<a href="http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf">Static Analysis for Regular Expression Denial-of-Service Attack</a>.
|
||||
<a href="https://arxiv.org/abs/1301.0849">Static Analysis for Regular Expression Denial-of-Service Attack</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -16,9 +16,14 @@ import semmle.javascript.security.dataflow.BrokenCryptoAlgorithmQuery
|
||||
import semmle.javascript.security.SensitiveActions
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
from
|
||||
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Source sourceNode,
|
||||
Sink sinkNode
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
not source.getNode() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash
|
||||
select sink.getNode(), source, sink, "A broken or weak cryptographic algorithm depends on $@.",
|
||||
source.getNode(), "sensitive data from " + source.getNode().(Source).describe()
|
||||
sourceNode = source.getNode() and
|
||||
sinkNode = sink.getNode() and
|
||||
not sourceNode instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash
|
||||
select sinkNode, source, sink, "$@ depends on $@.", sinkNode.getInitialization(),
|
||||
"A broken or weak cryptographic algorithm", sourceNode,
|
||||
"sensitive data from " + sourceNode.describe()
|
||||
|
||||
@@ -26,8 +26,8 @@ edges
|
||||
| tst.js:19:17:19:24 | password | tst.js:19:17:19:24 | password |
|
||||
| tst.js:22:21:22:30 | secretText | tst.js:22:21:22:30 | secretText |
|
||||
#select
|
||||
| tst.js:11:17:11:26 | secretText | tst.js:3:18:3:24 | trusted | tst.js:11:17:11:26 | secretText | A broken or weak cryptographic algorithm depends on $@. | tst.js:3:18:3:24 | trusted | sensitive data from an access to trusted |
|
||||
| tst.js:11:17:11:26 | secretText | tst.js:11:17:11:26 | secretText | tst.js:11:17:11:26 | secretText | A broken or weak cryptographic algorithm depends on $@. | tst.js:11:17:11:26 | secretText | sensitive data from an access to secretText |
|
||||
| tst.js:17:17:17:25 | o.trusted | tst.js:17:17:17:25 | o.trusted | tst.js:17:17:17:25 | o.trusted | A broken or weak cryptographic algorithm depends on $@. | tst.js:17:17:17:25 | o.trusted | sensitive data from an access to trusted |
|
||||
| tst.js:22:21:22:30 | secretText | tst.js:3:18:3:24 | trusted | tst.js:22:21:22:30 | secretText | A broken or weak cryptographic algorithm depends on $@. | tst.js:3:18:3:24 | trusted | sensitive data from an access to trusted |
|
||||
| tst.js:22:21:22:30 | secretText | tst.js:22:21:22:30 | secretText | tst.js:22:21:22:30 | secretText | A broken or weak cryptographic algorithm depends on $@. | tst.js:22:21:22:30 | secretText | sensitive data from an access to secretText |
|
||||
| tst.js:11:17:11:26 | secretText | tst.js:3:18:3:24 | trusted | tst.js:11:17:11:26 | secretText | $@ depends on $@. | tst.js:5:19:5:49 | crypto. ... ', key) | A broken or weak cryptographic algorithm | tst.js:3:18:3:24 | trusted | sensitive data from an access to trusted |
|
||||
| tst.js:11:17:11:26 | secretText | tst.js:11:17:11:26 | secretText | tst.js:11:17:11:26 | secretText | $@ depends on $@. | tst.js:5:19:5:49 | crypto. ... ', key) | A broken or weak cryptographic algorithm | tst.js:11:17:11:26 | secretText | sensitive data from an access to secretText |
|
||||
| tst.js:17:17:17:25 | o.trusted | tst.js:17:17:17:25 | o.trusted | tst.js:17:17:17:25 | o.trusted | $@ depends on $@. | tst.js:5:19:5:49 | crypto. ... ', key) | A broken or weak cryptographic algorithm | tst.js:17:17:17:25 | o.trusted | sensitive data from an access to trusted |
|
||||
| tst.js:22:21:22:30 | secretText | tst.js:3:18:3:24 | trusted | tst.js:22:21:22:30 | secretText | $@ depends on $@. | tst.js:21:22:21:60 | crypto. ... ', key) | A broken or weak cryptographic algorithm | tst.js:3:18:3:24 | trusted | sensitive data from an access to trusted |
|
||||
| tst.js:22:21:22:30 | secretText | tst.js:22:21:22:30 | secretText | tst.js:22:21:22:30 | secretText | $@ depends on $@. | tst.js:21:22:21:60 | crypto. ... ', key) | A broken or weak cryptographic algorithm | tst.js:22:21:22:30 | secretText | sensitive data from an access to secretText |
|
||||
|
||||
@@ -1352,7 +1352,10 @@ abstract class DataFlowCall extends TDataFlowCall {
|
||||
abstract ControlFlowNode getNode();
|
||||
|
||||
/** Gets the enclosing callable of this call. */
|
||||
abstract DataFlowCallable getEnclosingCallable();
|
||||
DataFlowCallable getEnclosingCallable() { result = getCallableScope(this.getScope()) }
|
||||
|
||||
/** Gets the scope of this node, if any. */
|
||||
abstract Scope getScope();
|
||||
|
||||
/** Gets the location of this dataflow call. */
|
||||
abstract Location getLocation();
|
||||
@@ -1400,7 +1403,7 @@ class NormalCall extends ExtractedDataFlowCall, TNormalCall {
|
||||
|
||||
override ControlFlowNode getNode() { result = call }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() }
|
||||
override Scope getScope() { result = call.getScope() }
|
||||
|
||||
override DataFlowCallable getCallable() { result.(DataFlowFunction).getScope() = target }
|
||||
|
||||
@@ -1450,7 +1453,7 @@ class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall
|
||||
|
||||
override ControlFlowNode getNode() { result = call }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() }
|
||||
override Scope getScope() { result = call.getScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1474,6 +1477,8 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
|
||||
|
||||
override Scope getScope() { none() }
|
||||
|
||||
override DataFlowCallable getCallable() { none() }
|
||||
|
||||
override ArgumentNode getArgument(ArgumentPosition apos) { none() }
|
||||
|
||||
@@ -1044,3 +1044,11 @@ class ContentApprox = Unit;
|
||||
/** Gets an approximated value for content `c`. */
|
||||
pragma[inline]
|
||||
ContentApprox getContentApprox(Content c) { any() }
|
||||
|
||||
/** Helper for `.getEnclosingCallable`. */
|
||||
DataFlowCallable getCallableScope(Scope s) {
|
||||
result.getScope() = s
|
||||
or
|
||||
not exists(DataFlowCallable c | c.getScope() = s) and
|
||||
result = getCallableScope(s.getEnclosingScope())
|
||||
}
|
||||
|
||||
@@ -117,14 +117,6 @@ newtype TNode =
|
||||
exists(ParameterPosition ppos | ppos.isKeyword(_) | exists(callable.getParameter(ppos)))
|
||||
}
|
||||
|
||||
/** Helper for `Node::getEnclosingCallable`. */
|
||||
private DataFlowCallable getCallableScope(Scope s) {
|
||||
result.getScope() = s
|
||||
or
|
||||
not exists(DataFlowCallable c | c.getScope() = s) and
|
||||
result = getCallableScope(s.getEnclosingScope())
|
||||
}
|
||||
|
||||
private import semmle.python.internal.CachedStages
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user