mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge branch 'main' into shared-http-client-request
This commit is contained in:
2136
cpp/downgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme
Normal file
2136
cpp/downgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add relation for orphaned local variables
|
||||
compatibility: full
|
||||
orphaned_variables.rel: delete
|
||||
@@ -292,22 +292,20 @@ module SemanticExprConfig {
|
||||
|
||||
class Guard = IRGuards::IRGuardCondition;
|
||||
|
||||
predicate guard(Guard guard, BasicBlock block) {
|
||||
block = guard.(IRGuards::IRGuardCondition).getBlock()
|
||||
}
|
||||
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
|
||||
|
||||
Expr getGuardAsExpr(Guard guard) { result = guard }
|
||||
|
||||
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
|
||||
guard.(IRGuards::IRGuardCondition).comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
|
||||
guard.controls(controlled, branch)
|
||||
}
|
||||
|
||||
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
|
||||
guard.controlsEdge(bb1, bb2, branch)
|
||||
}
|
||||
|
||||
Guard comparisonGuard(Expr e) { result = e }
|
||||
|
||||
@@ -218,8 +218,6 @@ class Folder extends Container, @folder {
|
||||
class File extends Container, @file {
|
||||
override string getAbsolutePath() { files(underlyingElement(this), result) }
|
||||
|
||||
override string toString() { result = Container.super.toString() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "File" }
|
||||
|
||||
override Location getLocation() {
|
||||
|
||||
@@ -398,6 +398,8 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
|
||||
or
|
||||
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
|
||||
or
|
||||
orphaned_variables(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -523,6 +523,11 @@ autoderivation(
|
||||
int derivation_type: @type ref
|
||||
);
|
||||
|
||||
orphaned_variables(
|
||||
int var: @localvariable ref,
|
||||
int function: @function ref
|
||||
)
|
||||
|
||||
enumconstants(
|
||||
unique int id: @enumconstant,
|
||||
int parent: @usertype ref,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add relation for orphaned local variables
|
||||
compatibility: partial
|
||||
@@ -106,6 +106,26 @@ predicate inheritanceConversionTypes(
|
||||
toType = convert.getResultType()
|
||||
}
|
||||
|
||||
private signature class ConversionInstruction extends UnaryInstruction;
|
||||
|
||||
module Conversion<ConversionInstruction I> {
|
||||
signature predicate hasTypes(I instr, Type fromType, Type toType);
|
||||
|
||||
module Using<hasTypes/3 project> {
|
||||
pragma[nomagic]
|
||||
predicate hasOperandAndTypes(I convert, Instruction unary, Type fromType, Type toType) {
|
||||
project(convert, fromType, toType) and
|
||||
unary = convert.getUnary()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasObjectAndField(FieldAddressInstruction fai, Instruction object, Field f) {
|
||||
fai.getObjectAddress() = object and
|
||||
fai.getField() = f
|
||||
}
|
||||
|
||||
/** Gets the HashCons value of an address computed by `instr`, if any. */
|
||||
TGlobalAddress globalAddress(Instruction instr) {
|
||||
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
|
||||
@@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
|
||||
result = TLoad(globalAddress(load.getSourceAddress()))
|
||||
)
|
||||
or
|
||||
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert |
|
||||
uncheckedConversionTypes(convert, fromType, toType) and
|
||||
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType)
|
||||
exists(Type fromType, Type toType, Instruction unary |
|
||||
Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
|
||||
unary, fromType, toType) and
|
||||
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
|
||||
)
|
||||
or
|
||||
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert |
|
||||
checkedConversionTypes(convert, fromType, toType) and
|
||||
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType)
|
||||
exists(Type fromType, Type toType, Instruction unary |
|
||||
Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
|
||||
unary, fromType, toType) and
|
||||
result = TConversion("checked", globalAddress(unary), fromType, toType)
|
||||
)
|
||||
or
|
||||
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert |
|
||||
inheritanceConversionTypes(convert, fromType, toType) and
|
||||
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType)
|
||||
exists(Type fromType, Type toType, Instruction unary |
|
||||
Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
|
||||
unary, fromType, toType) and
|
||||
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
|
||||
)
|
||||
or
|
||||
exists(FieldAddressInstruction fai | instr = fai |
|
||||
result =
|
||||
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())),
|
||||
pragma[only_bind_out](fai.getField()))
|
||||
exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
|
||||
hasObjectAndField(fai, object, f) and
|
||||
result = TFieldAddress(globalAddress(object), f)
|
||||
)
|
||||
or
|
||||
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
|
||||
@@ -268,7 +290,11 @@ class PathElement extends TPathElement {
|
||||
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
|
||||
|
||||
string toString() {
|
||||
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
|
||||
result =
|
||||
[
|
||||
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
|
||||
this.asSink(_).toString()
|
||||
]
|
||||
}
|
||||
|
||||
predicate hasLocationInfo(
|
||||
|
||||
@@ -19,6 +19,7 @@ import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import DataFlow::PathGraph
|
||||
@@ -83,6 +84,32 @@ class ExecState extends DataFlow::FlowState {
|
||||
DataFlow::Node getFstNode() { result = fst }
|
||||
|
||||
DataFlow::Node getSndNode() { result = snd }
|
||||
|
||||
/** Holds if this is a possible `ExecState` for `sink`. */
|
||||
predicate isFeasibleForSink(DataFlow::Node sink) {
|
||||
any(ExecStateConfiguration conf).hasFlow(snd, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
|
||||
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
|
||||
* `ExecTaintConfiguration::isSink`.
|
||||
*/
|
||||
class ExecStateConfiguration extends TaintTracking2::Configuration {
|
||||
ExecStateConfiguration() { this = "ExecStateConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(ExecState state | state.getSndNode() = source)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _)
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
@@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _) and
|
||||
state instanceof ExecState
|
||||
any(ExecStateConfiguration conf).isSink(sink) and
|
||||
state.(ExecState).isFeasibleForSink(sink)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(
|
||||
|
||||
@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
|
||||
exists(FunctionCall fc |
|
||||
fc = exp and
|
||||
(
|
||||
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
|
||||
fc.getEnclosingStmt().getParentStmt*() instanceof Loop and
|
||||
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
|
||||
not fc.getArgument(0).isConstant() and
|
||||
not fc.getArgument(1).isConstant() and
|
||||
|
||||
@@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
|
||||
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
|
||||
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||
or
|
||||
e0.(FunctionCall)
|
||||
.getTarget()
|
||||
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
|
||||
.getType()
|
||||
.getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||
e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
|
||||
mexp.getConversion().getConversion().getType().getSize()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
|
||||
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
|
||||
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
|
||||
(
|
||||
not exists(DivExpr de | mexp.getParent*() = de)
|
||||
not mexp.getParent*() instanceof DivExpr
|
||||
or
|
||||
exists(DivExpr de, Expr ec |
|
||||
e2.isConstant() and
|
||||
|
||||
@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
|
||||
override Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
private predicate onSameLine(ValidExpectation a, ActualResult b) {
|
||||
exists(string fname, int line, Location la, Location lb |
|
||||
// Join order intent:
|
||||
// Take the locations of ActualResults,
|
||||
// join with locations in the same file / on the same line,
|
||||
// then match those against ValidExpectations.
|
||||
la = a.getLocation() and
|
||||
pragma[only_bind_into](lb) = b.getLocation() and
|
||||
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
|
||||
lb.hasLocationInfo(fname, line, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string tag;
|
||||
string value;
|
||||
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string getKnownFailure() { result = knownFailure }
|
||||
|
||||
predicate matchesActualResult(ActualResult actualResult) {
|
||||
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
|
||||
getLocation().getFile() = actualResult.getLocation().getFile() and
|
||||
onSameLine(pragma[only_bind_into](this), actualResult) and
|
||||
getTag() = actualResult.getTag() and
|
||||
getValue() = actualResult.getValue()
|
||||
}
|
||||
|
||||
@@ -14137,6 +14137,30 @@ ir.cpp:
|
||||
# 1845| Type = [Struct] B
|
||||
# 1845| ValueCategory = lvalue
|
||||
# 1846| getStmt(2): [ReturnStmt] return ...
|
||||
# 1849| [TopLevelFunction] void magicvars()
|
||||
# 1849| <params>:
|
||||
# 1849| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1850| getStmt(0): [DeclStmt] declaration
|
||||
# 1850| getDeclarationEntry(0): [VariableDeclarationEntry] definition of pf
|
||||
# 1850| Type = [PointerType] const char *
|
||||
# 1850| getVariable().getInitializer(): [Initializer] initializer for pf
|
||||
# 1850| getExpr(): [VariableAccess] __PRETTY_FUNCTION__
|
||||
# 1850| Type = [ArrayType] const char[17]
|
||||
# 1850| ValueCategory = lvalue
|
||||
# 1850| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 1850| Type = [PointerType] const char *
|
||||
# 1850| ValueCategory = prvalue
|
||||
# 1851| getStmt(1): [DeclStmt] declaration
|
||||
# 1851| getDeclarationEntry(0): [VariableDeclarationEntry] definition of strfunc
|
||||
# 1851| Type = [PointerType] const char *
|
||||
# 1851| getVariable().getInitializer(): [Initializer] initializer for strfunc
|
||||
# 1851| getExpr(): [VariableAccess] __func__
|
||||
# 1851| Type = [ArrayType] const char[10]
|
||||
# 1851| ValueCategory = lvalue
|
||||
# 1851| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 1851| Type = [PointerType] const char *
|
||||
# 1851| ValueCategory = prvalue
|
||||
# 1852| getStmt(2): [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
@@ -1846,4 +1846,9 @@ namespace block_assignment {
|
||||
}
|
||||
}
|
||||
|
||||
void magicvars() {
|
||||
const char *pf = __PRETTY_FUNCTION__;
|
||||
const char *strfunc = __func__;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -8641,6 +8641,15 @@
|
||||
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_9 |
|
||||
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_12 |
|
||||
| ir.cpp:1845:13:1845:13 | Unary | r1845_3 |
|
||||
| ir.cpp:1849:6:1849:14 | ChiPartial | partial:m1849_3 |
|
||||
| ir.cpp:1849:6:1849:14 | ChiTotal | total:m1849_2 |
|
||||
| ir.cpp:1849:6:1849:14 | SideEffect | m1849_3 |
|
||||
| ir.cpp:1850:17:1850:18 | Address | &:r1850_1 |
|
||||
| ir.cpp:1850:22:1850:40 | StoreValue | r1850_3 |
|
||||
| ir.cpp:1850:22:1850:40 | Unary | r1850_2 |
|
||||
| ir.cpp:1851:17:1851:23 | Address | &:r1851_1 |
|
||||
| ir.cpp:1851:27:1851:34 | StoreValue | r1851_3 |
|
||||
| ir.cpp:1851:27:1851:34 | Unary | r1851_2 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
|
||||
|
||||
@@ -9914,6 +9914,24 @@ ir.cpp:
|
||||
# 1843| v1843_5(void) = AliasedUse : ~m?
|
||||
# 1843| v1843_6(void) = ExitFunction :
|
||||
|
||||
# 1849| void magicvars()
|
||||
# 1849| Block 0
|
||||
# 1849| v1849_1(void) = EnterFunction :
|
||||
# 1849| mu1849_2(unknown) = AliasedDefinition :
|
||||
# 1849| mu1849_3(unknown) = InitializeNonLocal :
|
||||
# 1850| r1850_1(glval<char *>) = VariableAddress[pf] :
|
||||
# 1850| r1850_2(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
|
||||
# 1850| r1850_3(char *) = Convert : r1850_2
|
||||
# 1850| mu1850_4(char *) = Store[pf] : &:r1850_1, r1850_3
|
||||
# 1851| r1851_1(glval<char *>) = VariableAddress[strfunc] :
|
||||
# 1851| r1851_2(glval<char[10]>) = VariableAddress[__func__] :
|
||||
# 1851| r1851_3(char *) = Convert : r1851_2
|
||||
# 1851| mu1851_4(char *) = Store[strfunc] : &:r1851_1, r1851_3
|
||||
# 1852| v1852_1(void) = NoOp :
|
||||
# 1849| v1849_4(void) = ReturnVoid :
|
||||
# 1849| v1849_5(void) = AliasedUse : ~m?
|
||||
# 1849| v1849_6(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -99,8 +99,6 @@ thisArgumentIsNonPointer
|
||||
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
nonUniqueIRVariable
|
||||
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -149,8 +149,6 @@ thisArgumentIsNonPointer
|
||||
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
nonUniqueIRVariable
|
||||
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -99,8 +99,6 @@ thisArgumentIsNonPointer
|
||||
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
nonUniqueIRVariable
|
||||
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -309,8 +309,6 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
|
||||
/** Gets the calling convention. */
|
||||
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
|
||||
|
||||
override string toString() { result = Type.super.toString() }
|
||||
|
||||
/** Holds if the return type is `void`. */
|
||||
predicate returnsVoid() { this.getReturnType() instanceof VoidType }
|
||||
|
||||
|
||||
@@ -215,11 +215,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
|
||||
/** Gets a `Call` that has this callable as a target. */
|
||||
Call getACall() { this = result.getTarget() }
|
||||
|
||||
override Parameter getParameter(int n) { result = Parameterizable.super.getParameter(n) }
|
||||
|
||||
override Parameter getAParameter() { result = Parameterizable.super.getAParameter() }
|
||||
|
||||
override int getNumberOfParameters() { result = Parameterizable.super.getNumberOfParameters() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,8 +272,6 @@ class Method extends Callable, Virtualizable, Attributable, @method {
|
||||
predicate hasParams() { exists(this.getParamsType()) }
|
||||
|
||||
// Remove when `Callable.isOverridden()` is removed
|
||||
override predicate isOverridden() { Virtualizable.super.isOverridden() }
|
||||
|
||||
override predicate fromSource() {
|
||||
Callable.super.fromSource() and
|
||||
not this.isCompilerGenerated()
|
||||
@@ -472,8 +466,6 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
|
||||
override Constructor getConstructor() {
|
||||
result = DotNet::RecordCloneCallable.super.getConstructor()
|
||||
}
|
||||
|
||||
override string toString() { result = Method.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,10 +116,6 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac
|
||||
override Location getALocation() { result = this.getADeclaration().getALocation() }
|
||||
|
||||
override string toString() { result = DotNet::Namespace.super.toString() }
|
||||
|
||||
override predicate hasQualifiedName(string a, string b) {
|
||||
DotNet::Namespace.super.hasQualifiedName(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,8 +42,6 @@ class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attribut
|
||||
}
|
||||
|
||||
override Type getType() { none() }
|
||||
|
||||
override string toString() { result = AssignableMember.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -163,10 +163,6 @@ module Ssa {
|
||||
* (`ImplicitDefinition`), or a phi node (`PhiNode`).
|
||||
*/
|
||||
class Definition extends SsaImpl::Definition {
|
||||
final override SourceVariable getSourceVariable() {
|
||||
result = SsaImpl::Definition.super.getSourceVariable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the control flow node of this SSA definition, if any. Phi nodes are
|
||||
* examples of SSA definitions without a control flow node, as they are
|
||||
|
||||
@@ -105,15 +105,12 @@ class DataFlowSummarizedCallable instanceof FlowSummary::SummarizedCallable {
|
||||
private module Cached {
|
||||
/**
|
||||
* The following heuristic is used to rank when to use source code or when to use summaries for DataFlowCallables.
|
||||
* 1. Use hand written summaries.
|
||||
* 2. Use source code.
|
||||
* 3. Use auto generated summaries.
|
||||
* 1. Use hand written summaries or source code.
|
||||
* 2. Use auto generated summaries.
|
||||
*/
|
||||
cached
|
||||
newtype TDataFlowCallable =
|
||||
TDotNetCallable(DotNet::Callable c) {
|
||||
c.isUnboundDeclaration() and not c instanceof DataFlowSummarizedCallable
|
||||
} or
|
||||
TDotNetCallable(DotNet::Callable c) { c.isUnboundDeclaration() } or
|
||||
TSummarizedCallable(DataFlowSummarizedCallable sc)
|
||||
|
||||
cached
|
||||
@@ -370,7 +367,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
|
||||
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override string toString() { result = cfn.toString() }
|
||||
@@ -400,7 +397,7 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
|
||||
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override string toString() { result = cfn.toString() }
|
||||
@@ -419,14 +416,14 @@ class TransitiveCapturedDataFlowCall extends DataFlowCall, TTransitiveCapturedCa
|
||||
|
||||
TransitiveCapturedDataFlowCall() { this = TTransitiveCapturedCall(cfn, target) }
|
||||
|
||||
override DataFlowCallable getARuntimeTarget() { result.getUnderlyingCallable() = target }
|
||||
override DataFlowCallable getARuntimeTarget() { result.asCallable() = target }
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
|
||||
|
||||
override DataFlow::ExprNode getNode() { none() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override string toString() { result = "[transitive] " + cfn.toString() }
|
||||
@@ -450,7 +447,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall {
|
||||
override DataFlow::ExprNode getNode() { result.getExpr() = call }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.getUnderlyingCallable() = call.getEnclosingCallable()
|
||||
result.asCallable() = call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
@@ -65,9 +65,11 @@ abstract class NodeImpl extends Node {
|
||||
|
||||
private class ExprNodeImpl extends ExprNode, NodeImpl {
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = this.getExpr().(CIL::Expr).getEnclosingCallable()
|
||||
or
|
||||
result.getUnderlyingCallable() = this.getControlFlowNodeImpl().getEnclosingCallable()
|
||||
result.asCallable() =
|
||||
[
|
||||
this.getExpr().(CIL::Expr).getEnclosingCallable().(DotNet::Callable),
|
||||
this.getControlFlowNodeImpl().getEnclosingCallable()
|
||||
]
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() {
|
||||
@@ -852,7 +854,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
|
||||
Ssa::Definition getDefinition() { result = def }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = def.getEnclosingCallable()
|
||||
result.asCallable() = def.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = def.getSourceVariable().getType() }
|
||||
@@ -914,9 +916,7 @@ private module ParameterNodes {
|
||||
callable = c.asCallable() and pos.isThisParameter()
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = callable
|
||||
}
|
||||
override DataFlowCallable getEnclosingCallableImpl() { result.asCallable() = callable }
|
||||
|
||||
override Type getTypeImpl() { result = callable.getDeclaringType() }
|
||||
|
||||
@@ -963,7 +963,7 @@ private module ParameterNodes {
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
pos.isImplicitCapturedParameterPosition(def.getSourceVariable().getAssignable()) and
|
||||
c.getUnderlyingCallable() = this.getEnclosingCallable()
|
||||
c.asCallable() = this.getEnclosingCallable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1078,7 +1078,7 @@ private module ArgumentNodes {
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = v.getType() }
|
||||
@@ -1107,7 +1107,7 @@ private module ArgumentNodes {
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
|
||||
@@ -1146,7 +1146,7 @@ private module ArgumentNodes {
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = callCfn.getEnclosingCallable()
|
||||
result.asCallable() = callCfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = this.getParameter().getType() }
|
||||
@@ -1227,7 +1227,7 @@ private module ReturnNodes {
|
||||
override NormalReturnKind getKind() { any() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = yrs.getEnclosingCallable()
|
||||
result.asCallable() = yrs.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() }
|
||||
@@ -1253,7 +1253,7 @@ private module ReturnNodes {
|
||||
override NormalReturnKind getKind() { any() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = expr.getEnclosingCallable()
|
||||
result.asCallable() = expr.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() }
|
||||
@@ -1330,9 +1330,10 @@ private module ReturnNodes {
|
||||
* In this case we adjust it to instead be a return node.
|
||||
*/
|
||||
private predicate summaryPostUpdateNodeIsOutOrRef(SummaryNode n, Parameter p) {
|
||||
exists(ParameterNode pn |
|
||||
exists(ParameterNodeImpl pn, DataFlowCallable c, ParameterPosition pos |
|
||||
FlowSummaryImpl::Private::summaryPostUpdateNode(n, pn) and
|
||||
pn.getParameter() = p and
|
||||
pn.isParameterOf(c, pos) and
|
||||
p = c.asSummarizedCallable().getParameter(pos.getPosition()) and
|
||||
p.isOutOrRef()
|
||||
)
|
||||
}
|
||||
@@ -1903,7 +1904,7 @@ private module PostUpdateNodes {
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() { result = oc.getType() }
|
||||
@@ -1923,7 +1924,7 @@ private module PostUpdateNodes {
|
||||
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
|
||||
result.asCallable() = cfn.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
|
||||
@@ -2012,12 +2013,11 @@ class LambdaCallKind = Unit;
|
||||
/** Holds if `creation` is an expression that creates a delegate for `c`. */
|
||||
predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(Expr e | e = creation.getExpr() |
|
||||
c.getUnderlyingCallable() = e.(AnonymousFunctionExpr)
|
||||
or
|
||||
c.getUnderlyingCallable() = e.(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
or
|
||||
c.getUnderlyingCallable() =
|
||||
c.asCallable() =
|
||||
[
|
||||
e.(AnonymousFunctionExpr), e.(CallableAccess).getTarget().getUnboundDeclaration(),
|
||||
e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
]
|
||||
) and
|
||||
kind = TMkUnit()
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class Node extends TNode {
|
||||
|
||||
/** Gets the enclosing callable of this node. */
|
||||
final Callable getEnclosingCallable() {
|
||||
result = this.(NodeImpl).getEnclosingCallableImpl().getUnderlyingCallable()
|
||||
result = this.(NodeImpl).getEnclosingCallableImpl().asCallable()
|
||||
}
|
||||
|
||||
/** Gets the control flow node corresponding to this node, if any. */
|
||||
@@ -103,7 +103,7 @@ class ParameterNode extends Node instanceof ParameterNodeImpl {
|
||||
DotNet::Parameter getParameter() {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
super.isParameterOf(c, ppos) and
|
||||
result = c.getUnderlyingCallable().getParameter(ppos.getPosition())
|
||||
result = c.asCallable().getParameter(ppos.getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -553,7 +553,7 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
|
||||
final override Callable getARuntimeTarget() {
|
||||
exists(ExplicitDelegateLikeDataFlowCall call |
|
||||
this = call.getCall() and
|
||||
result = viableCallableLambda(call, _).getUnderlyingCallable()
|
||||
result = viableCallableLambda(call, _).asCallable()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -357,3 +357,36 @@ class MicrosoftAspNetCoreHttpHtmlString extends Class {
|
||||
this.hasQualifiedName("Microsoft.AspNetCore.Html", "HtmlString")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions` class.
|
||||
*/
|
||||
class MicrosoftAspNetCoreBuilderEndpointRouteBuilderExtensions extends Class {
|
||||
MicrosoftAspNetCoreBuilderEndpointRouteBuilderExtensions() {
|
||||
this.hasQualifiedName("Microsoft.AspNetCore.Builder", "EndpointRouteBuilderExtensions")
|
||||
}
|
||||
|
||||
/** Gets the `Map` extension method. */
|
||||
Method getMapMethod() { result = this.getAMethod("Map") }
|
||||
|
||||
/** Gets the `MapGet` extension method. */
|
||||
Method getMapGetMethod() { result = this.getAMethod("MapGet") }
|
||||
|
||||
/** Gets the `MapPost` extension method. */
|
||||
Method getMapPostMethod() { result = this.getAMethod("MapPost") }
|
||||
|
||||
/** Gets the `MapPut` extension method. */
|
||||
Method getMapPutMethod() { result = this.getAMethod("MapPut") }
|
||||
|
||||
/** Gets the `MapDelete` extension method. */
|
||||
Method getMapDeleteMethod() { result = this.getAMethod("MapDelete") }
|
||||
|
||||
/** Get a `Map` like extenion methods. */
|
||||
Method getAMapMethod() {
|
||||
result =
|
||||
[
|
||||
this.getMapMethod(), this.getMapGetMethod(), this.getMapPostMethod(),
|
||||
this.getMapPutMethod(), this.getMapDeleteMethod()
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,35 @@ class ActionMethodParameter extends RemoteFlowSource, DataFlow::ParameterNode {
|
||||
/** A data flow source of remote user input (ASP.NET Core). */
|
||||
abstract class AspNetCoreRemoteFlowSource extends RemoteFlowSource { }
|
||||
|
||||
private predicate reachesMapGetArg(DataFlow::Node n) {
|
||||
exists(MethodCall mc |
|
||||
mc.getTarget() = any(MicrosoftAspNetCoreBuilderEndpointRouteBuilderExtensions c).getAMapMethod() and
|
||||
n.asExpr() = mc.getArgument(2)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Node mid | reachesMapGetArg(mid) |
|
||||
DataFlow::localFlowStep(n, mid) or
|
||||
n.asExpr() = mid.asExpr().(DelegateCreation).getArgument()
|
||||
)
|
||||
}
|
||||
|
||||
/** A parameter to a routing method delegate. */
|
||||
class AspNetCoreRoutingMethodParameter extends AspNetCoreRemoteFlowSource, DataFlow::ParameterNode {
|
||||
AspNetCoreRoutingMethodParameter() {
|
||||
exists(DataFlow::Node n, Callable c |
|
||||
reachesMapGetArg(n) and
|
||||
c.getAParameter() = this.asParameter() and
|
||||
c.isSourceDeclaration()
|
||||
|
|
||||
n.asExpr() = c
|
||||
or
|
||||
n.asExpr().(CallableAccess).getTarget().getUnboundDeclaration() = c
|
||||
)
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "ASP.NET Core routing endpoint." }
|
||||
}
|
||||
|
||||
/**
|
||||
* Data flow for ASP.NET Core.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Parameters of delegates passed to routing endpoint calls like `MapGet` in ASP.NET Core are now considered remote flow sources.
|
||||
@@ -817,10 +817,6 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
else result = this.getInstruction(AddressTag())
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
result = TranslatedVariableAccess.super.getInstructionOperand(tag, operandTag)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) {
|
||||
TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
|
||||
@@ -21,10 +21,6 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla
|
||||
result = "compiler generated declaration (" + generatedBy.toString() + ")"
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = LocalVariableDeclarationBase.super.getChild(id)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getInstruction(InitializerStoreTag())
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
|
||||
* Gets the enclosing callable of `ret`.
|
||||
*/
|
||||
CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
|
||||
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).getUnderlyingCallable()
|
||||
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
|
||||
override Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
private predicate onSameLine(ValidExpectation a, ActualResult b) {
|
||||
exists(string fname, int line, Location la, Location lb |
|
||||
// Join order intent:
|
||||
// Take the locations of ActualResults,
|
||||
// join with locations in the same file / on the same line,
|
||||
// then match those against ValidExpectations.
|
||||
la = a.getLocation() and
|
||||
pragma[only_bind_into](lb) = b.getLocation() and
|
||||
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
|
||||
lb.hasLocationInfo(fname, line, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string tag;
|
||||
string value;
|
||||
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string getKnownFailure() { result = knownFailure }
|
||||
|
||||
predicate matchesActualResult(ActualResult actualResult) {
|
||||
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
|
||||
getLocation().getFile() = actualResult.getLocation().getFile() and
|
||||
onSameLine(pragma[only_bind_into](this), actualResult) and
|
||||
getTag() = actualResult.getTag() and
|
||||
getValue() = actualResult.getValue()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
|
||||
namespace Testing
|
||||
{
|
||||
@@ -20,4 +22,40 @@ namespace Testing
|
||||
throw null;
|
||||
}
|
||||
}
|
||||
|
||||
public class Item
|
||||
{
|
||||
public string Tainted { get; set; }
|
||||
}
|
||||
|
||||
public class AspRoutingEndpoints
|
||||
{
|
||||
public delegate void MapGetHandler(string param);
|
||||
|
||||
public void HandlerMethod(string param) { }
|
||||
|
||||
public void M1(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var app = builder.Build();
|
||||
|
||||
// The delegate parameters are considered flow sources.
|
||||
app.MapGet("/api/redirect/{newUrl}", (string newUrl) => { });
|
||||
app.MapGet("/{myApi}/redirect/{myUrl}", (string myApi, string myUrl) => { });
|
||||
|
||||
Action<string> handler = (string lambdaParam) => { };
|
||||
app.MapGet("/api/redirect/{lambdaParam}", handler);
|
||||
|
||||
MapGetHandler handler2 = HandlerMethod;
|
||||
app.MapGet("/api/redirect/{mapGetParam}", handler2);
|
||||
|
||||
app.MapPost("/api/redirect/{mapPostParam}", (string mapPostParam) => { });
|
||||
app.MapPut("/api/redirect/{mapPutParam}", (string mapPutParam) => { });
|
||||
app.MapDelete("/api/redirect/{mapDeleteParam}", (string mapDeleteParam) => { });
|
||||
|
||||
app.MapPost("/items", (Item item) => { });
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,14 @@
|
||||
remoteFlowSourceMembers
|
||||
| AspRemoteFlowSource.cs:8:23:8:31 | RequestId |
|
||||
| AspRemoteFlowSource.cs:10:23:10:31 | RequestId |
|
||||
| AspRemoteFlowSource.cs:28:23:28:29 | Tainted |
|
||||
remoteFlowSources
|
||||
| AspRemoteFlowSource.cs:18:42:18:50 | viewModel |
|
||||
| AspRemoteFlowSource.cs:20:42:20:50 | viewModel |
|
||||
| AspRemoteFlowSource.cs:35:42:35:46 | param |
|
||||
| AspRemoteFlowSource.cs:43:58:43:63 | newUrl |
|
||||
| AspRemoteFlowSource.cs:44:61:44:65 | myApi |
|
||||
| AspRemoteFlowSource.cs:44:75:44:79 | myUrl |
|
||||
| AspRemoteFlowSource.cs:46:46:46:56 | lambdaParam |
|
||||
| AspRemoteFlowSource.cs:52:65:52:76 | mapPostParam |
|
||||
| AspRemoteFlowSource.cs:53:63:53:73 | mapPutParam |
|
||||
| AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam |
|
||||
| AspRemoteFlowSource.cs:56:41:56:44 | item |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// empty
|
||||
@@ -0,0 +1,62 @@
|
||||
// A hand-written test file that mimics the output of compiling a `.cshtml` file
|
||||
#pragma checksum "Index.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "c4ae76542f1958092cebd8f57beef899d20fc548"
|
||||
// <auto-generated/>
|
||||
#pragma warning disable 1591
|
||||
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(dotnetweb.Pages.Pages_Index), @"mvc.1.0.razor-page", @"Index.cshtml")]
|
||||
namespace dotnetweb.Pages
|
||||
{
|
||||
#line hidden
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
#nullable restore
|
||||
using dotnetweb;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#nullable disable
|
||||
[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"c4ae76542f1958092cebd8f57beef899d20fc548", @"Index.cshtml")]
|
||||
// [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"c13da96c2597d5ddb7d415fb4892c644a268f50b", @"/Pages/_ViewImports.cshtml")]
|
||||
public class Pages_Index : global::Microsoft.AspNetCore.Mvc.RazorPages.Page
|
||||
{
|
||||
#pragma warning disable 1998
|
||||
public async override global::System.Threading.Tasks.Task ExecuteAsync()
|
||||
{
|
||||
#nullable restore
|
||||
#line 3 "Index.cshtml"
|
||||
|
||||
ViewData["Title"] = "ASP.NET Core";
|
||||
var message = Request.Query["m"];
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#nullable disable
|
||||
WriteLiteral("<div class=\"cli\">\n <div class=\"cli-example\"> \n");
|
||||
#nullable restore
|
||||
#line 14 "Index.cshtml"
|
||||
Write(Html.Raw(message)); // BAD
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#nullable disable
|
||||
WriteLiteral("\n </div>\n</div>\n\n\n");
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
|
||||
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
|
||||
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
|
||||
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
|
||||
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
|
||||
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
|
||||
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
|
||||
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
|
||||
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
|
||||
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<string> Html { get; private set; }
|
||||
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<string> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<string>)PageContext?.ViewData;
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
@@ -1,4 +1,5 @@
|
||||
edges
|
||||
| Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | Index.cshtml:14:16:14:22 | call to operator implicit conversion |
|
||||
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:19:25:19:52 | access to indexer : String |
|
||||
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:26:30:26:34 | access to local variable sayHi |
|
||||
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:36:40:36:44 | access to local variable sayHi |
|
||||
@@ -14,6 +15,8 @@ edges
|
||||
| XSSAspNetCore.cs:61:44:61:63 | access to indexer : StringValues | XSSAspNetCore.cs:61:44:61:66 | access to indexer |
|
||||
| XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion |
|
||||
nodes
|
||||
| Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | semmle.label | access to property Query : IQueryCollection |
|
||||
| Index.cshtml:14:16:14:22 | call to operator implicit conversion | semmle.label | call to operator implicit conversion |
|
||||
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSSAspNet.cs:19:25:19:52 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSSAspNet.cs:26:30:26:34 | access to local variable sayHi | semmle.label | access to local variable sayHi |
|
||||
@@ -36,6 +39,7 @@ nodes
|
||||
| XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | semmle.label | call to operator implicit conversion |
|
||||
subpaths
|
||||
#select
|
||||
| Index.cshtml:14:16:14:22 | call to operator implicit conversion | Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | Index.cshtml:14:16:14:22 | call to operator implicit conversion | $@ flows to here and is written to HTML or JavaScript: Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw() method. | Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | User-provided value |
|
||||
| XSSAspNet.cs:26:30:26:34 | access to local variable sayHi | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:26:30:26:34 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteral() method. | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSSAspNet.cs:36:40:36:44 | access to local variable sayHi | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:36:40:36:44 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteralTo() method. | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSSAspNet.cs:43:28:43:55 | access to indexer | XSSAspNet.cs:43:28:43:46 | access to property QueryString : NameValueCollection | XSSAspNet.cs:43:28:43:55 | access to indexer | $@ flows to here and is written to HTML or JavaScript. | XSSAspNet.cs:43:28:43:46 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
|
||||
@@ -46,5 +46,3 @@ namespace ASP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// source-extractor-options: /r:${testdir}/../../../../../packages/Microsoft.AspNet.WebPages.3.2.3/lib/net45/System.Web.WebPages.dll /r:${testdir}/../../../../../packages/Microsoft.AspNet.Mvc.5.2.3/lib/net45/System.Web.Mvc.dll /r:System.Dynamic.Runtime.dll /r:System.Runtime.Extensions.dll /r:System.Linq.Expressions.dll /r:System.Web.dll /r:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.dll /r:System.Collections.Specialized.dll
|
||||
|
||||
@@ -75,5 +75,3 @@ namespace Testing.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initial-extractor-options: /r:netstandard.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.Core.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.Core.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Antiforgery.1.1.2/lib/net451/Microsoft.AspNetCore.Antiforgery.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.ViewFeatures.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.ViewFeatures.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.Abstractions.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.Abstractions.dll /r:${testdir}/../../../../../packages\Microsoft.AspNetCore.Http.Abstractions.1.1.2\lib\net451\Microsoft.AspNetCore.Http.Abstractions.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Html.Abstractions.1.1.2/lib/netstandard1.0/Microsoft.AspNetCore.Html.Abstractions.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Http.Features.1.1.2\lib\net451\Microsoft.AspNetCore.Http.Features.dll /r:${testdir}/../../../../../packages\Microsoft.Extensions.Primitives.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll /r:System.Linq.dll /r:System.Linq.Expressions.dll /r:System.Linq.Queryable.dll
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported.
|
||||
.. [2] Support for the clang-cl compiler is preliminary.
|
||||
.. [3] Support for the Arm Compiler (armcc) is preliminary.
|
||||
.. [4] Builds that execute on Java 7 to 18 can be analyzed. The analysis understands Java 18 standard language features.
|
||||
.. [4] Builds that execute on Java 7 to 19 can be analyzed. The analysis understands Java 19 standard language features.
|
||||
.. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
|
||||
.. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
||||
.. [7] Requires glibc 2.17.
|
||||
|
||||
@@ -28,12 +28,12 @@ class AstNode extends @node, Locatable {
|
||||
/**
|
||||
* Gets a child node of this node.
|
||||
*/
|
||||
AstNode getAChild() { result = getChild(_) }
|
||||
AstNode getAChild() { result = this.getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of child nodes of this node.
|
||||
*/
|
||||
int getNumChild() { result = count(getAChild()) }
|
||||
int getNumChild() { result = count(this.getAChild()) }
|
||||
|
||||
/**
|
||||
* Gets a child with the given index and of the given kind, if one exists.
|
||||
@@ -63,7 +63,7 @@ class AstNode extends @node, Locatable {
|
||||
AstNode getUniquelyNumberedChild(int index) {
|
||||
result =
|
||||
rank[index + 1](AstNode child, string kind, int i |
|
||||
child = getChildOfKind(kind, i)
|
||||
child = this.getChildOfKind(kind, i)
|
||||
|
|
||||
child order by kind, i
|
||||
)
|
||||
@@ -74,17 +74,17 @@ class AstNode extends @node, Locatable {
|
||||
|
||||
/** Gets the parent node of this AST node, but without crossing function boundaries. */
|
||||
private AstNode parentInSameFunction() {
|
||||
result = getParent() and
|
||||
result = this.getParent() and
|
||||
not this instanceof FuncDef
|
||||
}
|
||||
|
||||
/** Gets the innermost function definition to which this AST node belongs, if any. */
|
||||
FuncDef getEnclosingFunction() { result = getParent().parentInSameFunction*() }
|
||||
FuncDef getEnclosingFunction() { result = this.getParent().parentInSameFunction*() }
|
||||
|
||||
/**
|
||||
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
||||
*/
|
||||
final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") }
|
||||
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
|
||||
|
||||
/**
|
||||
* Gets the name of a primary CodeQL class to which this node belongs.
|
||||
@@ -116,12 +116,12 @@ class ExprParent extends @exprparent, AstNode {
|
||||
/**
|
||||
* Gets an expression that is a child node of this node in the AST.
|
||||
*/
|
||||
Expr getAChildExpr() { result = getChildExpr(_) }
|
||||
Expr getAChildExpr() { result = this.getChildExpr(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of child expressions of this node.
|
||||
*/
|
||||
int getNumChildExpr() { result = count(getAChildExpr()) }
|
||||
int getNumChildExpr() { result = count(this.getAChildExpr()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,12 +139,12 @@ class GoModExprParent extends @modexprparent, AstNode {
|
||||
/**
|
||||
* Gets an expression that is a child node of this node in the AST.
|
||||
*/
|
||||
GoModExpr getAChildGoModExpr() { result = getChildGoModExpr(_) }
|
||||
GoModExpr getAChildGoModExpr() { result = this.getChildGoModExpr(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of child expressions of this node.
|
||||
*/
|
||||
int getNumChildGoModExpr() { result = count(getAChildGoModExpr()) }
|
||||
int getNumChildGoModExpr() { result = count(this.getAChildGoModExpr()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,12 +162,12 @@ class StmtParent extends @stmtparent, AstNode {
|
||||
/**
|
||||
* Gets a statement that is a child node of this node in the AST.
|
||||
*/
|
||||
Stmt getAChildStmt() { result = getChildStmt(_) }
|
||||
Stmt getAChildStmt() { result = this.getChildStmt(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of child statements of this node.
|
||||
*/
|
||||
int getNumChildStmt() { result = count(getAChildStmt()) }
|
||||
int getNumChildStmt() { result = count(this.getAChildStmt()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,12 +185,12 @@ class DeclParent extends @declparent, AstNode {
|
||||
/**
|
||||
* Gets a child declaration of this node in the AST.
|
||||
*/
|
||||
Decl getADecl() { result = getDecl(_) }
|
||||
Decl getADecl() { result = this.getDecl(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of child declarations of this node.
|
||||
*/
|
||||
int getNumDecl() { result = count(getADecl()) }
|
||||
int getNumDecl() { result = count(this.getADecl()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,12 +208,12 @@ class FieldParent extends @fieldparent, AstNode {
|
||||
/**
|
||||
* Gets a child field of this node in the AST.
|
||||
*/
|
||||
FieldBase getAField() { result = getField(_) }
|
||||
FieldBase getAField() { result = this.getField(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of child fields of this node.
|
||||
*/
|
||||
int getNumFields() { result = count(getAField()) }
|
||||
int getNumFields() { result = count(this.getAField()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -787,7 +787,7 @@ class InterfaceType extends @interfacetype, CompositeType {
|
||||
* Note that the indexes are not contiguous.
|
||||
*/
|
||||
TypeSetLiteralType getDirectlyEmbeddedTypeSetLiteral(int index) {
|
||||
hasDirectlyEmbeddedType(index, result)
|
||||
this.hasDirectlyEmbeddedType(index, result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -798,7 +798,7 @@ class InterfaceType extends @interfacetype, CompositeType {
|
||||
TypeSetLiteralType getAnEmbeddedTypeSetLiteral() {
|
||||
result = this.getDirectlyEmbeddedTypeSetLiteral(_) or
|
||||
result =
|
||||
getADirectlyEmbeddedInterface()
|
||||
this.getADirectlyEmbeddedInterface()
|
||||
.getUnderlyingType()
|
||||
.(InterfaceType)
|
||||
.getAnEmbeddedTypeSetLiteral()
|
||||
|
||||
@@ -166,21 +166,11 @@ module ControlFlow {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node writes `rhs` to `channel`.
|
||||
*/
|
||||
predicate writesToChannel(DataFlow::ExprNode channel, DataFlow::ExprNode rhs) {
|
||||
exists(SendStmt send |
|
||||
send.getChannel() = channel.asExpr() and
|
||||
send.getValue() = rhs.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node sets any field or element of `base` to `rhs`.
|
||||
*/
|
||||
predicate writesComponent(DataFlow::Node base, DataFlow::Node rhs) {
|
||||
writesElement(base, _, rhs) or writesField(base, _, rhs) or writesToChannel(base, rhs)
|
||||
writesElement(base, _, rhs) or writesField(base, _, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ predicate containerStoreStep(Node node1, Node node2, Content c) {
|
||||
)
|
||||
or
|
||||
c instanceof CollectionContent and
|
||||
exists(Write w | w.writesToChannel(node2, node1))
|
||||
exists(SendStmt send |
|
||||
send.getChannel() = node2.(ExprNode).asExpr() and send.getValue() = node1.(ExprNode).asExpr()
|
||||
)
|
||||
or
|
||||
c instanceof MapKeyContent and
|
||||
node2.getType() instanceof MapType and
|
||||
|
||||
@@ -634,7 +634,10 @@ module Public {
|
||||
predicate isReceiverOf(MethodDecl m) { parm.isReceiverOf(m) }
|
||||
}
|
||||
|
||||
private Node getADirectlyWrittenNode() { exists(Write w | w.writesComponent(result, _)) }
|
||||
private Node getADirectlyWrittenNode() {
|
||||
exists(Write w | w.writesComponent(result, _)) or
|
||||
result = DataFlow::exprNode(any(SendStmt s).getChannel())
|
||||
}
|
||||
|
||||
private DataFlow::Node getAccessPathPredecessor(DataFlow::Node node) {
|
||||
result = node.(PointerDereferenceNode).getOperand()
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/**
|
||||
* Provides classes for working with concepts relating to the [github.com/elazarl/goproxy](https://pkg.go.dev/github.com/elazarl/goproxy) package.
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/**
|
||||
* Provides models of commonly used functions in the `github.com/golang/glog` packages and its
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */
|
||||
module Logrus {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/**
|
||||
* Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/**
|
||||
* Provides models of commonly used functions in the `go.uber.org/zap` package.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/** Provides models of commonly used functions in the `fmt` package. */
|
||||
module Fmt {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/** Provides models of commonly used functions in the `log` package. */
|
||||
module Log {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
|
||||
/**
|
||||
* Provides extension points for customizing the data-flow tracking configuration for reasoning
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.frameworks.SQL
|
||||
|
||||
from DataFlow::MethodCallNode call
|
||||
where
|
||||
|
||||
@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
|
||||
override Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
private predicate onSameLine(ValidExpectation a, ActualResult b) {
|
||||
exists(string fname, int line, Location la, Location lb |
|
||||
// Join order intent:
|
||||
// Take the locations of ActualResults,
|
||||
// join with locations in the same file / on the same line,
|
||||
// then match those against ValidExpectations.
|
||||
la = a.getLocation() and
|
||||
pragma[only_bind_into](lb) = b.getLocation() and
|
||||
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
|
||||
lb.hasLocationInfo(fname, line, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string tag;
|
||||
string value;
|
||||
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string getKnownFailure() { result = knownFailure }
|
||||
|
||||
predicate matchesActualResult(ActualResult actualResult) {
|
||||
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
|
||||
getLocation().getFile() = actualResult.getLocation().getFile() and
|
||||
onSameLine(pragma[only_bind_into](this), actualResult) and
|
||||
getTag() = actualResult.getTag() and
|
||||
getValue() = actualResult.getValue()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
edges
|
||||
| test.go:9:9:9:11 | selection of c [collection] : string | test.go:9:7:9:11 | <-... |
|
||||
| test.go:13:16:13:16 | definition of s [pointer, c, collection] : string | test.go:16:2:16:2 | s [pointer, c, collection] : string |
|
||||
| test.go:15:10:15:17 | call to source : string | test.go:16:9:16:12 | data : string |
|
||||
| test.go:16:2:16:2 | implicit dereference [c, collection] : string | test.go:13:16:13:16 | definition of s [pointer, c, collection] : string |
|
||||
| test.go:16:2:16:2 | implicit dereference [c, collection] : string | test.go:16:2:16:4 | selection of c [collection] : string |
|
||||
| test.go:16:2:16:2 | s [pointer, c, collection] : string | test.go:16:2:16:2 | implicit dereference [c, collection] : string |
|
||||
| test.go:16:2:16:4 | selection of c [collection] : string | test.go:9:9:9:11 | selection of c [collection] : string |
|
||||
| test.go:16:2:16:4 | selection of c [collection] : string | test.go:16:2:16:2 | implicit dereference [c, collection] : string |
|
||||
| test.go:16:9:16:12 | data : string | test.go:16:2:16:4 | selection of c [collection] : string |
|
||||
nodes
|
||||
| test.go:9:7:9:11 | <-... | semmle.label | <-... |
|
||||
| test.go:9:9:9:11 | selection of c [collection] : string | semmle.label | selection of c [collection] : string |
|
||||
| test.go:13:16:13:16 | definition of s [pointer, c, collection] : string | semmle.label | definition of s [pointer, c, collection] : string |
|
||||
| test.go:15:10:15:17 | call to source : string | semmle.label | call to source : string |
|
||||
| test.go:16:2:16:2 | implicit dereference [c, collection] : string | semmle.label | implicit dereference [c, collection] : string |
|
||||
| test.go:16:2:16:2 | s [pointer, c, collection] : string | semmle.label | s [pointer, c, collection] : string |
|
||||
| test.go:16:2:16:4 | selection of c [collection] : string | semmle.label | selection of c [collection] : string |
|
||||
| test.go:16:9:16:12 | data : string | semmle.label | data : string |
|
||||
subpaths
|
||||
#select
|
||||
| test.go:15:10:15:17 | call to source : string | test.go:15:10:15:17 | call to source : string | test.go:9:7:9:11 | <-... | path |
|
||||
@@ -0,0 +1,26 @@
|
||||
package test
|
||||
|
||||
type State struct {
|
||||
c chan string
|
||||
}
|
||||
|
||||
func handler(s *State) {
|
||||
|
||||
sink(<-s.c)
|
||||
|
||||
}
|
||||
|
||||
func requester(s *State) {
|
||||
|
||||
data := source()
|
||||
s.c <- data
|
||||
|
||||
}
|
||||
|
||||
func source() string {
|
||||
|
||||
return "tainted"
|
||||
|
||||
}
|
||||
|
||||
func sink(s string) {}
|
||||
@@ -0,0 +1,18 @@
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "test config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getTarget().getName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfig c
|
||||
where c.hasFlowPath(source, sink)
|
||||
select source, source, sink, "path"
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.dataflow.DataFlow
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
import CsvValidation
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import go
|
||||
import semmle.go.dataflow.DataFlow
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import CsvValidation
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import go
|
||||
import semmle.go.dataflow.DataFlow
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import CsvValidation
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import go
|
||||
import semmle.go.dataflow.DataFlow
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
import CsvValidation
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import go
|
||||
import semmle.go.frameworks.WebSocket
|
||||
|
||||
from WebSocketReader r, DataFlow::Node nd
|
||||
where nd = r.getAnOutput().getNode(r.getACall())
|
||||
|
||||
@@ -30,9 +30,22 @@ sourceSets {
|
||||
// change the excludes for building with other versions.
|
||||
// Currently 1.7.0 is configured:
|
||||
excludes = [
|
||||
"utils/versions/v_1_4_32/*.kt",
|
||||
"utils/versions/v_1_5_21/Descriptors.kt",
|
||||
"utils/versions/v_1_6_10/Descriptors.kt",
|
||||
// For 1.7.20-Beta, the below two files should be included, and the corresponding v_1_7_20-Beta ones should be excluded from this list.
|
||||
//"utils/versions/v_1_4_32/allOverriddenIncludingSelf.kt",
|
||||
//"utils/versions/v_1_4_32/createImplicitParameterDeclarationWithWrappedDescriptor.kt",
|
||||
"utils/versions/v_1_4_32/Descriptors.kt",
|
||||
"utils/versions/v_1_4_32/FileEntry.kt",
|
||||
"utils/versions/v_1_4_32/Functions.kt",
|
||||
"utils/versions/v_1_4_32/IsUnderscoreParameter.kt",
|
||||
"utils/versions/v_1_4_32/Psi2Ir.kt",
|
||||
"utils/versions/v_1_4_32/Types.kt",
|
||||
"utils/versions/v_1_4_32/withHasQuestionMark.kt",
|
||||
|
||||
"utils/versions/v_1_5_20/Descriptors.kt",
|
||||
"utils/versions/v_1_6_0/Descriptors.kt",
|
||||
|
||||
"utils/versions/v_1_7_20-Beta/createImplicitParameterDeclarationWithWrappedDescriptor.kt",
|
||||
"utils/versions/v_1_7_20-Beta/allOverriddenIncludingSelf.kt",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ def version_string_to_tuple(version):
|
||||
ci_version = '1.7.0'
|
||||
|
||||
# Version numbers in the list need to be in semantically increasing order
|
||||
many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.21', '1.5.31', '1.6.10', '1.6.20', '1.7.0' ]
|
||||
many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20-Beta' ]
|
||||
|
||||
many_versions_tuples = [version_string_to_tuple(v) for v in many_versions]
|
||||
|
||||
|
||||
@@ -4150,7 +4150,12 @@ open class KotlinFileExtractor(
|
||||
startIndex: Int = 0,
|
||||
reverse: Boolean = false
|
||||
) {
|
||||
extractTypeArguments((0 until c.typeArgumentsCount).map { c.getTypeArgument(it)!! }, tw.getLocation(c), parentExpr, enclosingCallable, enclosingStmt, startIndex, reverse)
|
||||
val typeArguments = (0 until c.typeArgumentsCount).map { c.getTypeArgument(it) }.requireNoNullsOrNull()
|
||||
if (typeArguments == null) {
|
||||
logger.errorElement("Found a null type argument for a member access expression", c)
|
||||
} else {
|
||||
extractTypeArguments(typeArguments, tw.getLocation(c), parentExpr, enclosingCallable, enclosingStmt, startIndex, reverse)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractArrayCreationWithInitializer(
|
||||
|
||||
@@ -5,12 +5,10 @@ import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
|
||||
import com.github.codeql.utils.versions.isRawType
|
||||
import com.semmle.extractor.java.OdasaOutput
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.allOverridden
|
||||
import org.jetbrains.kotlin.backend.common.ir.isFinalClass
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
@@ -26,7 +24,6 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.codeql.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.allOverridden
|
||||
import com.github.codeql.utils.versions.allOverriddenIncludingSelf
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -59,7 +59,7 @@ private val specialFunctionShortNames = specialFunctions.keys.map { it.functionN
|
||||
|
||||
private fun getSpecialJvmName(f: IrFunction): String? {
|
||||
if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) {
|
||||
f.allOverridden(true).forEach { overriddenFunc ->
|
||||
f.allOverriddenIncludingSelf().forEach { overriddenFunc ->
|
||||
overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName ->
|
||||
specialFunctions[MethodKey(parentFqName, f.name)]?.let {
|
||||
return it
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.github.codeql.utils
|
||||
import com.github.codeql.KotlinUsesExtractor
|
||||
import com.github.codeql.getJavaEquivalentClassId
|
||||
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
|
||||
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.classId
|
||||
import org.jetbrains.kotlin.ir.util.constructedClassType
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.backend.common.ir.allOverridden
|
||||
|
||||
fun IrSimpleFunction.allOverriddenIncludingSelf() = this.allOverridden(includeSelf = true)
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
|
||||
fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() = this.createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.util.allOverridden
|
||||
|
||||
fun IrSimpleFunction.allOverriddenIncludingSelf() = this.allOverridden(includeSelf = true)
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
|
||||
fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() = this.createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
4
java/ql/lib/change-notes/2022-08-19-java-19-support.md
Normal file
4
java/ql/lib/change-notes/2022-08-19-java-19-support.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Java 19 builds can now be extracted. There are no non-preview new language features in this release, so the only user-visible change is that the CodeQL extractor will now correctly trace compilations using the JDK 19 release of `javac`.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Classes and methods that are seen with several different paths during the extraction process (for example, packaged into different JAR files) now report an arbitrarily selected location via their `getLocation` and `hasLocationInfo` predicates, rather than reporting all of them. This may lead to reduced alert duplication.
|
||||
@@ -205,5 +205,19 @@ cached
|
||||
private predicate fixedHasLocation(Top l, Location loc, File f) {
|
||||
hasSourceLocation(l, loc, f)
|
||||
or
|
||||
hasLocation(l, loc) and not hasSourceLocation(l, _, _) and locations_default(loc, f, _, _, _, _)
|
||||
// When an entity has more than one location, as it might due to
|
||||
// e.g. a parameterized generic being seen and extracted in several
|
||||
// different directories or JAR files, select an arbitrary representative
|
||||
// location to avoid needlessly duplicating alerts.
|
||||
//
|
||||
// Don't do this when the relevant location is in a source file, because
|
||||
// that is much more unusual and we would rather notice the bug than mask it here.
|
||||
loc =
|
||||
min(Location candidateLoc |
|
||||
hasLocation(l, candidateLoc)
|
||||
|
|
||||
candidateLoc order by candidateLoc.getFile().toString()
|
||||
) and
|
||||
not hasSourceLocation(l, _, _) and
|
||||
locations_default(loc, f, _, _, _, _)
|
||||
}
|
||||
|
||||
@@ -9,21 +9,23 @@ private import semmle.code.java.frameworks.android.Android
|
||||
* The class `android.database.sqlite.SQLiteDatabase`.
|
||||
*/
|
||||
class TypeSQLiteDatabase extends Class {
|
||||
TypeSQLiteDatabase() { hasQualifiedName("android.database.sqlite", "SQLiteDatabase") }
|
||||
TypeSQLiteDatabase() { this.hasQualifiedName("android.database.sqlite", "SQLiteDatabase") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.database.sqlite.SQLiteQueryBuilder`.
|
||||
*/
|
||||
class TypeSQLiteQueryBuilder extends Class {
|
||||
TypeSQLiteQueryBuilder() { hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") }
|
||||
TypeSQLiteQueryBuilder() {
|
||||
this.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.database.DatabaseUtils`.
|
||||
*/
|
||||
class TypeDatabaseUtils extends Class {
|
||||
TypeDatabaseUtils() { hasQualifiedName("android.database", "DatabaseUtils") }
|
||||
TypeDatabaseUtils() { this.hasQualifiedName("android.database", "DatabaseUtils") }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ private class FileSetRedableMethodAccess extends MethodAccess {
|
||||
private predicate isCallToSecondArgumentWithValue(boolean value) {
|
||||
this.getMethod().getNumberOfParameters() = 1 and value = true
|
||||
or
|
||||
isCallWithArgument(1, value)
|
||||
this.isCallWithArgument(1, value)
|
||||
}
|
||||
|
||||
private predicate isCallWithArgument(int index, boolean arg) {
|
||||
|
||||
@@ -23,7 +23,8 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and
|
||||
sink.asExpr() instanceof VarAccess
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
@@ -31,18 +32,17 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
smallExpr(node.asExpr()) or
|
||||
node.getEnclosingCallable() instanceof HashCodeMethod
|
||||
node.getEnclosingCallable() instanceof HashCodeMethod or
|
||||
exists(RightShiftOp e | e.getShiftedVariable().getAnAccess() = node.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp,
|
||||
VarAccess tainted, NumericCastFlowConfig conf
|
||||
NumericCastFlowConfig conf
|
||||
where
|
||||
exp.getExpr() = tainted and
|
||||
sink.getNode().asExpr() = tainted and
|
||||
conf.hasFlowPath(source, sink) and
|
||||
not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable())
|
||||
sink.getNode().asExpr() = exp.getExpr() and
|
||||
conf.hasFlowPath(source, sink)
|
||||
select exp, source, sink,
|
||||
"$@ flows to here and is cast to a narrower type, potentially causing truncation.",
|
||||
source.getNode(), "User-provided value"
|
||||
|
||||
@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
|
||||
override Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
private predicate onSameLine(ValidExpectation a, ActualResult b) {
|
||||
exists(string fname, int line, Location la, Location lb |
|
||||
// Join order intent:
|
||||
// Take the locations of ActualResults,
|
||||
// join with locations in the same file / on the same line,
|
||||
// then match those against ValidExpectations.
|
||||
la = a.getLocation() and
|
||||
pragma[only_bind_into](lb) = b.getLocation() and
|
||||
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
|
||||
lb.hasLocationInfo(fname, line, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string tag;
|
||||
string value;
|
||||
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string getKnownFailure() { result = knownFailure }
|
||||
|
||||
predicate matchesActualResult(ActualResult actualResult) {
|
||||
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
|
||||
getLocation().getFile() = actualResult.getLocation().getFile() and
|
||||
onSameLine(pragma[only_bind_into](this), actualResult) and
|
||||
getTag() = actualResult.getTag() and
|
||||
getValue() = actualResult.getValue()
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
| A.kt:4:21:4:29 | someFun(...) | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | someFun | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | C<D1,D2,E1,E2> | OC.class:0:0:0:0 | OC<F1,F2> |
|
||||
| A.kt:4:21:4:29 | someFun(...) | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | someFun | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | C<D1,D2,E1,E2> | file:///!unknown-binary-location/OC.class:0:0:0:0 | OC<F1,F2> |
|
||||
|
||||
@@ -234,8 +234,6 @@ class File extends Container, @file {
|
||||
/** Gets a toplevel piece of JavaScript code in this file. */
|
||||
TopLevel getATopLevel() { result.getFile() = this }
|
||||
|
||||
override string toString() { result = Container.super.toString() }
|
||||
|
||||
/** Gets the URL of this file. */
|
||||
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
|
||||
|
||||
@@ -147,30 +147,22 @@ private string getASrcFolderName() { result = ["ts", "js", "src", "lib"] }
|
||||
*/
|
||||
class MainModulePath extends PathExpr, @json_string {
|
||||
PackageJson pkg;
|
||||
string relativePath;
|
||||
|
||||
MainModulePath() {
|
||||
relativePath = "." and
|
||||
this = pkg.getPropValue(["main", "module"])
|
||||
or
|
||||
// { "exports": "path" } is sugar for { "exports": { ".": "path" }}
|
||||
relativePath = "." and
|
||||
this = pkg.getPropValue("exports")
|
||||
or
|
||||
exists(JsonValue val | val = pkg.getPropValue("exports").getPropValue(relativePath) |
|
||||
// Either specified directly as a string: { "./path": "./path.js" }
|
||||
this = val
|
||||
or
|
||||
// Or by module type: { "./path": { "require": "./path.cjs", ... }}
|
||||
this = val.getPropValue(_)
|
||||
)
|
||||
this = getAPartOfExportsSection(pkg)
|
||||
}
|
||||
|
||||
/** Gets the `package.json` file in which this path occurs. */
|
||||
PackageJson getPackageJson() { result = pkg }
|
||||
|
||||
/** Gets the relative path under which this is exported, usually starting with a `.`. */
|
||||
string getRelativePath() { result = relativePath }
|
||||
string getRelativePath() {
|
||||
result = getExportRelativePath(this)
|
||||
or
|
||||
not exists(getExportRelativePath(this)) and result = "."
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getPackageJson */
|
||||
deprecated PackageJSON getPackageJSON() { result = getPackageJson() }
|
||||
@@ -183,6 +175,29 @@ class MainModulePath extends PathExpr, @json_string {
|
||||
}
|
||||
}
|
||||
|
||||
private JsonValue getAPartOfExportsSection(PackageJson pkg) {
|
||||
result = pkg.getPropValue("exports")
|
||||
or
|
||||
result = getAPartOfExportsSection(pkg).getPropValue(_)
|
||||
}
|
||||
|
||||
/** Gets the text of one of the conditions or paths enclosing the given `part` of an `exports` section. */
|
||||
private string getAnEnclosingExportProperty(JsonValue part) {
|
||||
exists(JsonObject parent, string prop |
|
||||
parent = getAPartOfExportsSection(_) and
|
||||
part = parent.getPropValue(prop)
|
||||
|
|
||||
result = prop
|
||||
or
|
||||
result = getAnEnclosingExportProperty(parent)
|
||||
)
|
||||
}
|
||||
|
||||
private string getExportRelativePath(JsonValue part) {
|
||||
result = getAnEnclosingExportProperty(part) and
|
||||
result.matches(".%")
|
||||
}
|
||||
|
||||
module MainModulePath {
|
||||
/** Gets the path to the main entry point of `pkg`. */
|
||||
MainModulePath of(PackageJson pkg) { result = of(pkg, ".") }
|
||||
|
||||
@@ -43,8 +43,6 @@ abstract private class BracketedListOfExpressions extends Expr {
|
||||
* An array expression viewed as a bracketed list of expressions.
|
||||
*/
|
||||
private class ArrayExprIsABracketedListOfExpressions extends ArrayExpr, BracketedListOfExpressions {
|
||||
override predicate isImpure() { ArrayExpr.super.isImpure() }
|
||||
|
||||
/** Gets the `i`th element of this array literal. */
|
||||
override Expr getElement(int i) { result = ArrayExpr.super.getElement(i) }
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import semmle.javascript.frameworks.Testing
|
||||
|
||||
class MyTest extends Test, CallExpr {
|
||||
MyTest() { getCallee().(VarAccess).getName() = "mytest" }
|
||||
|
||||
override string toString() { result = CallExpr.super.toString() }
|
||||
}
|
||||
|
||||
from Test t
|
||||
|
||||
@@ -68,8 +68,6 @@ class ListComp extends ListComp_, Comp {
|
||||
|
||||
override Expr getIterable() { result = ListComp_.super.getIterable() }
|
||||
|
||||
override string toString() { result = ListComp_.super.toString() }
|
||||
|
||||
override Expr getElt() { result = Comp.super.getElt() }
|
||||
}
|
||||
|
||||
|
||||
@@ -616,6 +616,9 @@ private string non_byte_prefix() {
|
||||
not result.charAt(_) in ["b", "B"]
|
||||
}
|
||||
|
||||
/** A string constant. This is a placeholder class -- use `StrConst` instead. */
|
||||
class Str = StrConst;
|
||||
|
||||
/** A string constant. */
|
||||
class StrConst extends Str_, ImmutableLiteral {
|
||||
/* syntax: "hello" */
|
||||
|
||||
@@ -2,8 +2,6 @@ import python
|
||||
|
||||
class KeyValuePair extends KeyValuePair_, DictDisplayItem {
|
||||
/* syntax: Expr : Expr */
|
||||
override Location getLocation() { result = KeyValuePair_.super.getLocation() }
|
||||
|
||||
override string toString() { result = KeyValuePair_.super.toString() }
|
||||
|
||||
/** Gets the value of this dictionary unpacking. */
|
||||
@@ -20,8 +18,6 @@ class KeyValuePair extends KeyValuePair_, DictDisplayItem {
|
||||
|
||||
/** A double-starred expression in a call or dict literal. */
|
||||
class DictUnpacking extends DictUnpacking_, DictUnpackingOrKeyword, DictDisplayItem {
|
||||
override Location getLocation() { result = DictUnpacking_.super.getLocation() }
|
||||
|
||||
override string toString() { result = DictUnpacking_.super.toString() }
|
||||
|
||||
/** Gets the value of this dictionary unpacking. */
|
||||
@@ -47,8 +43,6 @@ abstract class DictDisplayItem extends DictItem {
|
||||
/** A keyword argument in a call. For example `arg=expr` in `foo(0, arg=expr)` */
|
||||
class Keyword extends Keyword_, DictUnpackingOrKeyword {
|
||||
/* syntax: name = Expr */
|
||||
override Location getLocation() { result = Keyword_.super.getLocation() }
|
||||
|
||||
override string toString() { result = Keyword_.super.toString() }
|
||||
|
||||
/** Gets the value of this keyword argument. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user