Merge branch 'main' into shared-http-client-request

This commit is contained in:
Rasmus Wriedt Larsen
2022-08-22 12:05:37 +02:00
committed by GitHub
192 changed files with 10953 additions and 1801 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Add relation for orphaned local variables
compatibility: full
orphaned_variables.rel: delete

View File

@@ -292,22 +292,20 @@ module SemanticExprConfig {
class Guard = IRGuards::IRGuardCondition; class Guard = IRGuards::IRGuardCondition;
predicate guard(Guard guard, BasicBlock block) { predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
block = guard.(IRGuards::IRGuardCondition).getBlock()
}
Expr getGuardAsExpr(Guard guard) { result = guard } Expr getGuardAsExpr(Guard guard) { result = guard }
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) { 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) { 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) { 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 } Guard comparisonGuard(Expr e) { result = e }

View File

@@ -218,8 +218,6 @@ class Folder extends Container, @folder {
class File extends Container, @file { class File extends Container, @file {
override string getAbsolutePath() { files(underlyingElement(this), result) } override string getAbsolutePath() { files(underlyingElement(this), result) }
override string toString() { result = Container.super.toString() }
override string getAPrimaryQlClass() { result = "File" } override string getAPrimaryQlClass() { result = "File" }
override Location getLocation() { override Location getLocation() {

View File

@@ -398,6 +398,8 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result) exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
or or
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result) exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
or
orphaned_variables(underlyingElement(this), unresolveElement(result))
} }
} }

View File

@@ -523,6 +523,11 @@ autoderivation(
int derivation_type: @type ref int derivation_type: @type ref
); );
orphaned_variables(
int var: @localvariable ref,
int function: @function ref
)
enumconstants( enumconstants(
unique int id: @enumconstant, unique int id: @enumconstant,
int parent: @usertype ref, int parent: @usertype ref,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add relation for orphaned local variables
compatibility: partial

View File

@@ -106,6 +106,26 @@ predicate inheritanceConversionTypes(
toType = convert.getResultType() 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. */ /** Gets the HashCons value of an address computed by `instr`, if any. */
TGlobalAddress globalAddress(Instruction instr) { TGlobalAddress globalAddress(Instruction instr) {
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable()) result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
@@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
result = TLoad(globalAddress(load.getSourceAddress())) result = TLoad(globalAddress(load.getSourceAddress()))
) )
or or
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert | exists(Type fromType, Type toType, Instruction unary |
uncheckedConversionTypes(convert, fromType, toType) and Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType) unary, fromType, toType) and
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
) )
or or
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert | exists(Type fromType, Type toType, Instruction unary |
checkedConversionTypes(convert, fromType, toType) and Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType) unary, fromType, toType) and
result = TConversion("checked", globalAddress(unary), fromType, toType)
) )
or or
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert | exists(Type fromType, Type toType, Instruction unary |
inheritanceConversionTypes(convert, fromType, toType) and Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType) unary, fromType, toType) and
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
) )
or or
exists(FieldAddressInstruction fai | instr = fai | exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
result = hasObjectAndField(fai, object, f) and
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())), result = TFieldAddress(globalAddress(object), f)
pragma[only_bind_out](fai.getField()))
) )
or or
result = globalAddress(instr.(PointerOffsetInstruction).getLeft()) result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
@@ -268,7 +290,11 @@ class PathElement extends TPathElement {
predicate isSink(IRBlock block) { exists(this.asSink(block)) } predicate isSink(IRBlock block) { exists(this.asSink(block)) }
string toString() { 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( predicate hasLocationInfo(

View File

@@ -19,6 +19,7 @@ import semmle.code.cpp.security.Security
import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph import DataFlow::PathGraph
@@ -83,6 +84,32 @@ class ExecState extends DataFlow::FlowState {
DataFlow::Node getFstNode() { result = fst } DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd } 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 { class ExecTaintConfiguration extends TaintTracking::Configuration {
@@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
} }
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
shellCommand(sinkAsArgumentIndirection(sink), _) and any(ExecStateConfiguration conf).isSink(sink) and
state instanceof ExecState state.(ExecState).isFeasibleForSink(sink)
} }
override predicate isAdditionalTaintStep( override predicate isAdditionalTaintStep(

View File

@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
exists(FunctionCall fc | exists(FunctionCall fc |
fc = exp and 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 fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
not fc.getArgument(0).isConstant() and not fc.getArgument(0).isConstant() and
not fc.getArgument(1).isConstant() and not fc.getArgument(1).isConstant() and

View File

@@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize() e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
or or
e0.(FunctionCall) e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
.getTarget() mexp.getConversion().getConversion().getType().getSize()
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
.getType()
.getSize() = mexp.getConversion().getConversion().getType().getSize()
) )
) )
} }
@@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
( (
not exists(DivExpr de | mexp.getParent*() = de) not mexp.getParent*() instanceof DivExpr
or or
exists(DivExpr de, Expr ec | exists(DivExpr de, Expr ec |
e2.isConstant() and e2.isConstant() and

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() } 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 { private class ValidExpectation extends Expectation, TValidExpectation {
string tag; string tag;
string value; string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure } string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) { predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and onSameLine(pragma[only_bind_into](this), actualResult) and
getLocation().getFile() = actualResult.getLocation().getFile() and
getTag() = actualResult.getTag() and getTag() = actualResult.getTag() and
getValue() = actualResult.getValue() getValue() = actualResult.getValue()
} }

View File

@@ -14137,6 +14137,30 @@ ir.cpp:
# 1845| Type = [Struct] B # 1845| Type = [Struct] B
# 1845| ValueCategory = lvalue # 1845| ValueCategory = lvalue
# 1846| getStmt(2): [ReturnStmt] return ... # 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: perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>: # 4| <params>:

View File

@@ -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 // semmle-extractor-options: -std=c++17 --clang

View File

@@ -8641,6 +8641,15 @@
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_9 | | ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_9 |
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_12 | | ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_12 |
| ir.cpp:1845:13:1845:13 | Unary | r1845_3 | | 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_5 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -9914,6 +9914,24 @@ ir.cpp:
# 1843| v1843_5(void) = AliasedUse : ~m? # 1843| v1843_5(void) = AliasedUse : ~m?
# 1843| v1843_6(void) = ExitFunction : # 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: perf-regression.cpp:
# 6| void Big::Big() # 6| void Big::Big()
# 6| Block 0 # 6| Block 0

View File

@@ -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: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::*) | | 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 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 missingCanonicalLanguageType
multipleCanonicalLanguageTypes multipleCanonicalLanguageTypes
missingIRType missingIRType

View File

@@ -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: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::*) | | 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 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 missingCanonicalLanguageType
multipleCanonicalLanguageTypes multipleCanonicalLanguageTypes
missingIRType missingIRType

View File

@@ -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: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::*) | | 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 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 missingCanonicalLanguageType
multipleCanonicalLanguageTypes multipleCanonicalLanguageTypes
missingIRType missingIRType

View File

@@ -309,8 +309,6 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
/** Gets the calling convention. */ /** Gets the calling convention. */
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) } int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
override string toString() { result = Type.super.toString() }
/** Holds if the return type is `void`. */ /** Holds if the return type is `void`. */
predicate returnsVoid() { this.getReturnType() instanceof VoidType } predicate returnsVoid() { this.getReturnType() instanceof VoidType }

View File

@@ -215,11 +215,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
/** Gets a `Call` that has this callable as a target. */ /** Gets a `Call` that has this callable as a target. */
Call getACall() { this = result.getTarget() } Call getACall() { this = result.getTarget() }
override Parameter getParameter(int n) { result = Parameterizable.super.getParameter(n) }
override Parameter getAParameter() { result = Parameterizable.super.getAParameter() } 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()) } predicate hasParams() { exists(this.getParamsType()) }
// Remove when `Callable.isOverridden()` is removed // Remove when `Callable.isOverridden()` is removed
override predicate isOverridden() { Virtualizable.super.isOverridden() }
override predicate fromSource() { override predicate fromSource() {
Callable.super.fromSource() and Callable.super.fromSource() and
not this.isCompilerGenerated() not this.isCompilerGenerated()
@@ -472,8 +466,6 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
override Constructor getConstructor() { override Constructor getConstructor() {
result = DotNet::RecordCloneCallable.super.getConstructor() result = DotNet::RecordCloneCallable.super.getConstructor()
} }
override string toString() { result = Method.super.toString() }
} }
/** /**

View File

@@ -116,10 +116,6 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac
override Location getALocation() { result = this.getADeclaration().getALocation() } override Location getALocation() { result = this.getADeclaration().getALocation() }
override string toString() { result = DotNet::Namespace.super.toString() } override string toString() { result = DotNet::Namespace.super.toString() }
override predicate hasQualifiedName(string a, string b) {
DotNet::Namespace.super.hasQualifiedName(a, b)
}
} }
/** /**

View File

@@ -42,8 +42,6 @@ class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attribut
} }
override Type getType() { none() } override Type getType() { none() }
override string toString() { result = AssignableMember.super.toString() }
} }
/** /**

View File

@@ -163,10 +163,6 @@ module Ssa {
* (`ImplicitDefinition`), or a phi node (`PhiNode`). * (`ImplicitDefinition`), or a phi node (`PhiNode`).
*/ */
class Definition extends SsaImpl::Definition { 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 * 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 * examples of SSA definitions without a control flow node, as they are

View File

@@ -105,15 +105,12 @@ class DataFlowSummarizedCallable instanceof FlowSummary::SummarizedCallable {
private module Cached { private module Cached {
/** /**
* The following heuristic is used to rank when to use source code or when to use summaries for DataFlowCallables. * The following heuristic is used to rank when to use source code or when to use summaries for DataFlowCallables.
* 1. Use hand written summaries. * 1. Use hand written summaries or source code.
* 2. Use source code. * 2. Use auto generated summaries.
* 3. Use auto generated summaries.
*/ */
cached cached
newtype TDataFlowCallable = newtype TDataFlowCallable =
TDotNetCallable(DotNet::Callable c) { TDotNetCallable(DotNet::Callable c) { c.isUnboundDeclaration() } or
c.isUnboundDeclaration() and not c instanceof DataFlowSummarizedCallable
} or
TSummarizedCallable(DataFlowSummarizedCallable sc) TSummarizedCallable(DataFlowSummarizedCallable sc)
cached cached
@@ -370,7 +367,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn } override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override string toString() { result = cfn.toString() } override string toString() { result = cfn.toString() }
@@ -400,7 +397,7 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn } override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override string toString() { result = cfn.toString() } override string toString() { result = cfn.toString() }
@@ -419,14 +416,14 @@ class TransitiveCapturedDataFlowCall extends DataFlowCall, TTransitiveCapturedCa
TransitiveCapturedDataFlowCall() { this = TTransitiveCapturedCall(cfn, target) } 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 ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
override DataFlow::ExprNode getNode() { none() } override DataFlow::ExprNode getNode() { none() }
override DataFlowCallable getEnclosingCallable() { override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override string toString() { result = "[transitive] " + cfn.toString() } override string toString() { result = "[transitive] " + cfn.toString() }
@@ -450,7 +447,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall {
override DataFlow::ExprNode getNode() { result.getExpr() = call } override DataFlow::ExprNode getNode() { result.getExpr() = call }
override DataFlowCallable getEnclosingCallable() { override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = call.getEnclosingCallable() result.asCallable() = call.getEnclosingCallable()
} }
override string toString() { result = call.toString() } override string toString() { result = call.toString() }

View File

@@ -65,9 +65,11 @@ abstract class NodeImpl extends Node {
private class ExprNodeImpl extends ExprNode, NodeImpl { private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = this.getExpr().(CIL::Expr).getEnclosingCallable() result.asCallable() =
or [
result.getUnderlyingCallable() = this.getControlFlowNodeImpl().getEnclosingCallable() this.getExpr().(CIL::Expr).getEnclosingCallable().(DotNet::Callable),
this.getControlFlowNodeImpl().getEnclosingCallable()
]
} }
override DotNet::Type getTypeImpl() { override DotNet::Type getTypeImpl() {
@@ -852,7 +854,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
Ssa::Definition getDefinition() { result = def } Ssa::Definition getDefinition() { result = def }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = def.getEnclosingCallable() result.asCallable() = def.getEnclosingCallable()
} }
override Type getTypeImpl() { result = def.getSourceVariable().getType() } override Type getTypeImpl() { result = def.getSourceVariable().getType() }
@@ -914,9 +916,7 @@ private module ParameterNodes {
callable = c.asCallable() and pos.isThisParameter() callable = c.asCallable() and pos.isThisParameter()
} }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() { result.asCallable() = callable }
result.getUnderlyingCallable() = callable
}
override Type getTypeImpl() { result = callable.getDeclaringType() } override Type getTypeImpl() { result = callable.getDeclaringType() }
@@ -963,7 +963,7 @@ private module ParameterNodes {
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
pos.isImplicitCapturedParameterPosition(def.getSourceVariable().getAssignable()) and pos.isImplicitCapturedParameterPosition(def.getSourceVariable().getAssignable()) and
c.getUnderlyingCallable() = this.getEnclosingCallable() c.asCallable() = this.getEnclosingCallable()
} }
} }
@@ -1078,7 +1078,7 @@ private module ArgumentNodes {
} }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override Type getTypeImpl() { result = v.getType() } override Type getTypeImpl() { result = v.getType() }
@@ -1107,7 +1107,7 @@ private module ArgumentNodes {
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
@@ -1146,7 +1146,7 @@ private module ArgumentNodes {
} }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = callCfn.getEnclosingCallable() result.asCallable() = callCfn.getEnclosingCallable()
} }
override Type getTypeImpl() { result = this.getParameter().getType() } override Type getTypeImpl() { result = this.getParameter().getType() }
@@ -1227,7 +1227,7 @@ private module ReturnNodes {
override NormalReturnKind getKind() { any() } override NormalReturnKind getKind() { any() }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = yrs.getEnclosingCallable() result.asCallable() = yrs.getEnclosingCallable()
} }
override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() } override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() }
@@ -1253,7 +1253,7 @@ private module ReturnNodes {
override NormalReturnKind getKind() { any() } override NormalReturnKind getKind() { any() }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = expr.getEnclosingCallable() result.asCallable() = expr.getEnclosingCallable()
} }
override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() } 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. * In this case we adjust it to instead be a return node.
*/ */
private predicate summaryPostUpdateNodeIsOutOrRef(SummaryNode n, Parameter p) { private predicate summaryPostUpdateNodeIsOutOrRef(SummaryNode n, Parameter p) {
exists(ParameterNode pn | exists(ParameterNodeImpl pn, DataFlowCallable c, ParameterPosition pos |
FlowSummaryImpl::Private::summaryPostUpdateNode(n, pn) and FlowSummaryImpl::Private::summaryPostUpdateNode(n, pn) and
pn.getParameter() = p and pn.isParameterOf(c, pos) and
p = c.asSummarizedCallable().getParameter(pos.getPosition()) and
p.isOutOrRef() p.isOutOrRef()
) )
} }
@@ -1903,7 +1904,7 @@ private module PostUpdateNodes {
} }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override DotNet::Type getTypeImpl() { result = oc.getType() } override DotNet::Type getTypeImpl() { result = oc.getType() }
@@ -1923,7 +1924,7 @@ private module PostUpdateNodes {
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() } override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable() result.asCallable() = cfn.getEnclosingCallable()
} }
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } 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`. */ /** Holds if `creation` is an expression that creates a delegate for `c`. */
predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) { predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) {
exists(Expr e | e = creation.getExpr() | exists(Expr e | e = creation.getExpr() |
c.getUnderlyingCallable() = e.(AnonymousFunctionExpr) c.asCallable() =
or [
c.getUnderlyingCallable() = e.(CallableAccess).getTarget().getUnboundDeclaration() e.(AnonymousFunctionExpr), e.(CallableAccess).getTarget().getUnboundDeclaration(),
or e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
c.getUnderlyingCallable() = ]
e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
) and ) and
kind = TMkUnit() kind = TMkUnit()
} }

View File

@@ -41,7 +41,7 @@ class Node extends TNode {
/** Gets the enclosing callable of this node. */ /** Gets the enclosing callable of this node. */
final Callable getEnclosingCallable() { final Callable getEnclosingCallable() {
result = this.(NodeImpl).getEnclosingCallableImpl().getUnderlyingCallable() result = this.(NodeImpl).getEnclosingCallableImpl().asCallable()
} }
/** Gets the control flow node corresponding to this node, if any. */ /** Gets the control flow node corresponding to this node, if any. */
@@ -103,7 +103,7 @@ class ParameterNode extends Node instanceof ParameterNodeImpl {
DotNet::Parameter getParameter() { DotNet::Parameter getParameter() {
exists(DataFlowCallable c, ParameterPosition ppos | exists(DataFlowCallable c, ParameterPosition ppos |
super.isParameterOf(c, ppos) and super.isParameterOf(c, ppos) and
result = c.getUnderlyingCallable().getParameter(ppos.getPosition()) result = c.asCallable().getParameter(ppos.getPosition())
) )
} }

View File

@@ -553,7 +553,7 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
final override Callable getARuntimeTarget() { final override Callable getARuntimeTarget() {
exists(ExplicitDelegateLikeDataFlowCall call | exists(ExplicitDelegateLikeDataFlowCall call |
this = call.getCall() and this = call.getCall() and
result = viableCallableLambda(call, _).getUnderlyingCallable() result = viableCallableLambda(call, _).asCallable()
) )
} }

View File

@@ -357,3 +357,36 @@ class MicrosoftAspNetCoreHttpHtmlString extends Class {
this.hasQualifiedName("Microsoft.AspNetCore.Html", "HtmlString") 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()
]
}
}

View File

@@ -171,6 +171,35 @@ class ActionMethodParameter extends RemoteFlowSource, DataFlow::ParameterNode {
/** A data flow source of remote user input (ASP.NET Core). */ /** A data flow source of remote user input (ASP.NET Core). */
abstract class AspNetCoreRemoteFlowSource extends RemoteFlowSource { } 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. * Data flow for ASP.NET Core.
* *

View File

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

View File

@@ -817,10 +817,6 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
else result = this.getInstruction(AddressTag()) 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) { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) {
TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType) TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType)
or or

View File

@@ -21,10 +21,6 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla
result = "compiler generated declaration (" + generatedBy.toString() + ")" result = "compiler generated declaration (" + generatedBy.toString() + ")"
} }
override TranslatedElement getChild(int id) {
result = LocalVariableDeclarationBase.super.getChild(id)
}
override Instruction getChildSuccessor(TranslatedElement child) { override Instruction getChildSuccessor(TranslatedElement child) {
child = getInitialization() and result = getInstruction(InitializerStoreTag()) child = getInitialization() and result = getInstruction(InitializerStoreTag())
} }

View File

@@ -112,7 +112,7 @@ string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
* Gets the enclosing callable of `ret`. * Gets the enclosing callable of `ret`.
*/ */
CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) { CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).getUnderlyingCallable() result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
} }
/** /**

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() } 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 { private class ValidExpectation extends Expectation, TValidExpectation {
string tag; string tag;
string value; string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure } string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) { predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and onSameLine(pragma[only_bind_into](this), actualResult) and
getLocation().getFile() = actualResult.getLocation().getFile() and
getTag() = actualResult.getTag() and getTag() = actualResult.getTag() and
getValue() = actualResult.getValue() getValue() = actualResult.getValue()
} }

View File

@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System;
namespace Testing namespace Testing
{ {
@@ -20,4 +22,40 @@ namespace Testing
throw null; 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();
}
}
} }

View File

@@ -1,4 +1,14 @@
remoteFlowSourceMembers remoteFlowSourceMembers
| AspRemoteFlowSource.cs:8:23:8:31 | RequestId | | AspRemoteFlowSource.cs:10:23:10:31 | RequestId |
| AspRemoteFlowSource.cs:28:23:28:29 | Tainted |
remoteFlowSources 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 |

View File

@@ -0,0 +1 @@
// empty

View File

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

View File

@@ -1,4 +1,5 @@
edges 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: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: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 | | 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: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 | | XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion |
nodes 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: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: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 | | 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 | | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | semmle.label | call to operator implicit conversion |
subpaths subpaths
#select #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: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: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 | | 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 |

View File

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

View File

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

View File

@@ -30,7 +30,7 @@
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported. .. [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. .. [2] Support for the clang-cl compiler is preliminary.
.. [3] Support for the Arm Compiler (armcc) 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. .. [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. .. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
.. [7] Requires glibc 2.17. .. [7] Requires glibc 2.17.

View File

@@ -28,12 +28,12 @@ class AstNode extends @node, Locatable {
/** /**
* Gets a child node of this node. * 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. * 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. * 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) { AstNode getUniquelyNumberedChild(int index) {
result = result =
rank[index + 1](AstNode child, string kind, int i | rank[index + 1](AstNode child, string kind, int i |
child = getChildOfKind(kind, i) child = this.getChildOfKind(kind, i)
| |
child order by 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. */ /** Gets the parent node of this AST node, but without crossing function boundaries. */
private AstNode parentInSameFunction() { private AstNode parentInSameFunction() {
result = getParent() and result = this.getParent() and
not this instanceof FuncDef not this instanceof FuncDef
} }
/** Gets the innermost function definition to which this AST node belongs, if any. */ /** 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. * 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. * 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. * 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. * 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. * 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. * 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. * 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. * 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. * 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. * 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. * 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. * Gets the number of child fields of this node.
*/ */
int getNumFields() { result = count(getAField()) } int getNumFields() { result = count(this.getAField()) }
} }
/** /**

View File

@@ -787,7 +787,7 @@ class InterfaceType extends @interfacetype, CompositeType {
* Note that the indexes are not contiguous. * Note that the indexes are not contiguous.
*/ */
TypeSetLiteralType getDirectlyEmbeddedTypeSetLiteral(int index) { TypeSetLiteralType getDirectlyEmbeddedTypeSetLiteral(int index) {
hasDirectlyEmbeddedType(index, result) this.hasDirectlyEmbeddedType(index, result)
} }
/** /**
@@ -798,7 +798,7 @@ class InterfaceType extends @interfacetype, CompositeType {
TypeSetLiteralType getAnEmbeddedTypeSetLiteral() { TypeSetLiteralType getAnEmbeddedTypeSetLiteral() {
result = this.getDirectlyEmbeddedTypeSetLiteral(_) or result = this.getDirectlyEmbeddedTypeSetLiteral(_) or
result = result =
getADirectlyEmbeddedInterface() this.getADirectlyEmbeddedInterface()
.getUnderlyingType() .getUnderlyingType()
.(InterfaceType) .(InterfaceType)
.getAnEmbeddedTypeSetLiteral() .getAnEmbeddedTypeSetLiteral()

View File

@@ -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`. * Holds if this node sets any field or element of `base` to `rhs`.
*/ */
predicate writesComponent(DataFlow::Node base, DataFlow::Node 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)
} }
} }

View File

@@ -24,7 +24,9 @@ predicate containerStoreStep(Node node1, Node node2, Content c) {
) )
or or
c instanceof CollectionContent and 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 or
c instanceof MapKeyContent and c instanceof MapKeyContent and
node2.getType() instanceof MapType and node2.getType() instanceof MapType and

View File

@@ -634,7 +634,10 @@ module Public {
predicate isReceiverOf(MethodDecl m) { parm.isReceiverOf(m) } 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) { private DataFlow::Node getAccessPathPredecessor(DataFlow::Node node) {
result = node.(PointerDereferenceNode).getOperand() result = node.(PointerDereferenceNode).getOperand()

View File

@@ -3,7 +3,6 @@
*/ */
import go 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. * Provides classes for working with concepts relating to the [github.com/elazarl/goproxy](https://pkg.go.dev/github.com/elazarl/goproxy) package.

View File

@@ -4,7 +4,6 @@
*/ */
import go import go
private import semmle.go.StringOps
/** /**
* Provides models of commonly used functions in the `github.com/golang/glog` packages and its * Provides models of commonly used functions in the `github.com/golang/glog` packages and its

View File

@@ -1,7 +1,6 @@
/** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */ /** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */
import go import go
private import semmle.go.StringOps
/** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */ /** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */
module Logrus { module Logrus {

View File

@@ -3,7 +3,6 @@
*/ */
import go import go
private import semmle.go.StringOps
/** /**
* Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package. * Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package.

View File

@@ -3,7 +3,6 @@
*/ */
import go import go
private import semmle.go.StringOps
/** /**
* Provides models of commonly used functions in the `go.uber.org/zap` package. * Provides models of commonly used functions in the `go.uber.org/zap` package.

View File

@@ -3,7 +3,6 @@
*/ */
import go import go
private import semmle.go.StringOps
/** Provides models of commonly used functions in the `fmt` package. */ /** Provides models of commonly used functions in the `fmt` package. */
module Fmt { module Fmt {

View File

@@ -3,7 +3,6 @@
*/ */
import go import go
private import semmle.go.StringOps
/** Provides models of commonly used functions in the `log` package. */ /** Provides models of commonly used functions in the `log` package. */
module Log { module Log {

View File

@@ -4,7 +4,6 @@
*/ */
import go import go
private import semmle.go.StringOps
/** /**
* Provides extension points for customizing the data-flow tracking configuration for reasoning * Provides extension points for customizing the data-flow tracking configuration for reasoning

View File

@@ -9,7 +9,6 @@
*/ */
import go import go
import semmle.go.frameworks.SQL
from DataFlow::MethodCallNode call from DataFlow::MethodCallNode call
where where

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() } 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 { private class ValidExpectation extends Expectation, TValidExpectation {
string tag; string tag;
string value; string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure } string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) { predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and onSameLine(pragma[only_bind_into](this), actualResult) and
getLocation().getFile() = actualResult.getLocation().getFile() and
getTag() = actualResult.getTag() and getTag() = actualResult.getTag() and
getValue() = actualResult.getValue() getValue() = actualResult.getValue()
} }

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,6 @@
*/ */
import go import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow import semmle.go.dataflow.ExternalFlow
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation import CsvValidation

View File

@@ -1,5 +1,4 @@
import go import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow import semmle.go.dataflow.ExternalFlow
import CsvValidation import CsvValidation

View File

@@ -1,5 +1,4 @@
import go import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow import semmle.go.dataflow.ExternalFlow
import CsvValidation import CsvValidation

View File

@@ -1,5 +1,4 @@
import go import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow import semmle.go.dataflow.ExternalFlow
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation import CsvValidation

View File

@@ -1,5 +1,4 @@
import go import go
import semmle.go.frameworks.WebSocket
from WebSocketReader r, DataFlow::Node nd from WebSocketReader r, DataFlow::Node nd
where nd = r.getAnOutput().getNode(r.getACall()) where nd = r.getAnOutput().getNode(r.getACall())

View File

@@ -30,9 +30,22 @@ sourceSets {
// change the excludes for building with other versions. // change the excludes for building with other versions.
// Currently 1.7.0 is configured: // Currently 1.7.0 is configured:
excludes = [ excludes = [
"utils/versions/v_1_4_32/*.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_5_21/Descriptors.kt", //"utils/versions/v_1_4_32/allOverriddenIncludingSelf.kt",
"utils/versions/v_1_6_10/Descriptors.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",
] ]
} }
} }

View File

@@ -25,7 +25,7 @@ def version_string_to_tuple(version):
ci_version = '1.7.0' ci_version = '1.7.0'
# Version numbers in the list need to be in semantically increasing order # 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] many_versions_tuples = [version_string_to_tuple(v) for v in many_versions]

View File

@@ -4150,7 +4150,12 @@ open class KotlinFileExtractor(
startIndex: Int = 0, startIndex: Int = 0,
reverse: Boolean = false 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( private fun extractArrayCreationWithInitializer(

View File

@@ -5,12 +5,10 @@ import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
import com.github.codeql.utils.versions.isRawType import com.github.codeql.utils.versions.isRawType
import com.semmle.extractor.java.OdasaOutput import com.semmle.extractor.java.OdasaOutput
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.allOverridden import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.ir.isFinalClass
import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI 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.java.structure.*
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance

View File

@@ -1,6 +1,6 @@
package com.github.codeql.utils 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.builtins.StandardNames
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
import org.jetbrains.kotlin.ir.declarations.IrClass 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? { private fun getSpecialJvmName(f: IrFunction): String? {
if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) { if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) {
f.allOverridden(true).forEach { overriddenFunc -> f.allOverriddenIncludingSelf().forEach { overriddenFunc ->
overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName -> overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName ->
specialFunctions[MethodKey(parentFqName, f.name)]?.let { specialFunctions[MethodKey(parentFqName, f.name)]?.let {
return it return it

View File

@@ -3,8 +3,8 @@ package com.github.codeql.utils
import com.github.codeql.KotlinUsesExtractor import com.github.codeql.KotlinUsesExtractor
import com.github.codeql.getJavaEquivalentClassId import com.github.codeql.getJavaEquivalentClassId
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark 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.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor 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.classId
import org.jetbrains.kotlin.ir.util.constructedClassType import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.constructors 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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance

View File

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

View File

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

View File

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

View File

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

View 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`.

View File

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

View File

@@ -205,5 +205,19 @@ cached
private predicate fixedHasLocation(Top l, Location loc, File f) { private predicate fixedHasLocation(Top l, Location loc, File f) {
hasSourceLocation(l, loc, f) hasSourceLocation(l, loc, f)
or 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, _, _, _, _)
} }

View File

@@ -9,21 +9,23 @@ private import semmle.code.java.frameworks.android.Android
* The class `android.database.sqlite.SQLiteDatabase`. * The class `android.database.sqlite.SQLiteDatabase`.
*/ */
class TypeSQLiteDatabase extends Class { class TypeSQLiteDatabase extends Class {
TypeSQLiteDatabase() { hasQualifiedName("android.database.sqlite", "SQLiteDatabase") } TypeSQLiteDatabase() { this.hasQualifiedName("android.database.sqlite", "SQLiteDatabase") }
} }
/** /**
* The class `android.database.sqlite.SQLiteQueryBuilder`. * The class `android.database.sqlite.SQLiteQueryBuilder`.
*/ */
class TypeSQLiteQueryBuilder extends Class { class TypeSQLiteQueryBuilder extends Class {
TypeSQLiteQueryBuilder() { hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") } TypeSQLiteQueryBuilder() {
this.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder")
}
} }
/** /**
* The class `android.database.DatabaseUtils`. * The class `android.database.DatabaseUtils`.
*/ */
class TypeDatabaseUtils extends Class { class TypeDatabaseUtils extends Class {
TypeDatabaseUtils() { hasQualifiedName("android.database", "DatabaseUtils") } TypeDatabaseUtils() { this.hasQualifiedName("android.database", "DatabaseUtils") }
} }
/** /**

View File

@@ -53,7 +53,7 @@ private class FileSetRedableMethodAccess extends MethodAccess {
private predicate isCallToSecondArgumentWithValue(boolean value) { private predicate isCallToSecondArgumentWithValue(boolean value) {
this.getMethod().getNumberOfParameters() = 1 and value = true this.getMethod().getNumberOfParameters() = 1 and value = true
or or
isCallWithArgument(1, value) this.isCallWithArgument(1, value)
} }
private predicate isCallWithArgument(int index, boolean arg) { private predicate isCallWithArgument(int index, boolean arg) {

View File

@@ -23,7 +23,8 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { 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) { override predicate isSanitizer(DataFlow::Node node) {
@@ -31,18 +32,17 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
castCheck(node.asExpr()) or castCheck(node.asExpr()) or
node.getType() instanceof SmallType or node.getType() instanceof SmallType or
smallExpr(node.asExpr()) or smallExpr(node.asExpr()) or
node.getEnclosingCallable() instanceof HashCodeMethod node.getEnclosingCallable() instanceof HashCodeMethod or
exists(RightShiftOp e | e.getShiftedVariable().getAnAccess() = node.asExpr())
} }
} }
from from
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp, DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp,
VarAccess tainted, NumericCastFlowConfig conf NumericCastFlowConfig conf
where where
exp.getExpr() = tainted and sink.getNode().asExpr() = exp.getExpr() and
sink.getNode().asExpr() = tainted and conf.hasFlowPath(source, sink)
conf.hasFlowPath(source, sink) and
not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable())
select exp, source, sink, select exp, source, sink,
"$@ flows to here and is cast to a narrower type, potentially causing truncation.", "$@ flows to here and is cast to a narrower type, potentially causing truncation.",
source.getNode(), "User-provided value" source.getNode(), "User-provided value"

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() } 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 { private class ValidExpectation extends Expectation, TValidExpectation {
string tag; string tag;
string value; string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure } string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) { predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and onSameLine(pragma[only_bind_into](this), actualResult) and
getLocation().getFile() = actualResult.getLocation().getFile() and
getTag() = actualResult.getTag() and getTag() = actualResult.getTag() and
getValue() = actualResult.getValue() getValue() = actualResult.getValue()
} }

View File

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

View File

@@ -234,8 +234,6 @@ class File extends Container, @file {
/** Gets a toplevel piece of JavaScript code in this file. */ /** Gets a toplevel piece of JavaScript code in this file. */
TopLevel getATopLevel() { result.getFile() = this } TopLevel getATopLevel() { result.getFile() = this }
override string toString() { result = Container.super.toString() }
/** Gets the URL of this file. */ /** Gets the URL of this file. */
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }

View File

@@ -147,30 +147,22 @@ private string getASrcFolderName() { result = ["ts", "js", "src", "lib"] }
*/ */
class MainModulePath extends PathExpr, @json_string { class MainModulePath extends PathExpr, @json_string {
PackageJson pkg; PackageJson pkg;
string relativePath;
MainModulePath() { MainModulePath() {
relativePath = "." and
this = pkg.getPropValue(["main", "module"]) this = pkg.getPropValue(["main", "module"])
or or
// { "exports": "path" } is sugar for { "exports": { ".": "path" }} this = getAPartOfExportsSection(pkg)
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(_)
)
} }
/** Gets the `package.json` file in which this path occurs. */ /** Gets the `package.json` file in which this path occurs. */
PackageJson getPackageJson() { result = pkg } PackageJson getPackageJson() { result = pkg }
/** Gets the relative path under which this is exported, usually starting with a `.`. */ /** 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: Alias for getPackageJson */
deprecated PackageJSON getPackageJSON() { result = 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 { module MainModulePath {
/** Gets the path to the main entry point of `pkg`. */ /** Gets the path to the main entry point of `pkg`. */
MainModulePath of(PackageJson pkg) { result = of(pkg, ".") } MainModulePath of(PackageJson pkg) { result = of(pkg, ".") }

View File

@@ -43,8 +43,6 @@ abstract private class BracketedListOfExpressions extends Expr {
* An array expression viewed as a bracketed list of expressions. * An array expression viewed as a bracketed list of expressions.
*/ */
private class ArrayExprIsABracketedListOfExpressions extends ArrayExpr, BracketedListOfExpressions { private class ArrayExprIsABracketedListOfExpressions extends ArrayExpr, BracketedListOfExpressions {
override predicate isImpure() { ArrayExpr.super.isImpure() }
/** Gets the `i`th element of this array literal. */ /** Gets the `i`th element of this array literal. */
override Expr getElement(int i) { result = ArrayExpr.super.getElement(i) } override Expr getElement(int i) { result = ArrayExpr.super.getElement(i) }
} }

View File

@@ -17,4 +17,4 @@
"peerDependencies": { "peerDependencies": {
"tea": "2.x" "tea": "2.x"
} }
} }

View File

@@ -2,8 +2,6 @@ import semmle.javascript.frameworks.Testing
class MyTest extends Test, CallExpr { class MyTest extends Test, CallExpr {
MyTest() { getCallee().(VarAccess).getName() = "mytest" } MyTest() { getCallee().(VarAccess).getName() = "mytest" }
override string toString() { result = CallExpr.super.toString() }
} }
from Test t from Test t

View File

@@ -68,8 +68,6 @@ class ListComp extends ListComp_, Comp {
override Expr getIterable() { result = ListComp_.super.getIterable() } override Expr getIterable() { result = ListComp_.super.getIterable() }
override string toString() { result = ListComp_.super.toString() }
override Expr getElt() { result = Comp.super.getElt() } override Expr getElt() { result = Comp.super.getElt() }
} }

View File

@@ -616,6 +616,9 @@ private string non_byte_prefix() {
not result.charAt(_) in ["b", "B"] not result.charAt(_) in ["b", "B"]
} }
/** A string constant. This is a placeholder class -- use `StrConst` instead. */
class Str = StrConst;
/** A string constant. */ /** A string constant. */
class StrConst extends Str_, ImmutableLiteral { class StrConst extends Str_, ImmutableLiteral {
/* syntax: "hello" */ /* syntax: "hello" */

Some files were not shown because too many files have changed in this diff Show More