This commit is contained in:
Asger Feldthaus 2020-02-27 09:41:01 +00:00
Родитель 9c06c48dc7
Коммит fefcf1a7a6
130 изменённых файлов: 657 добавлений и 774 удалений

Просмотреть файл

@ -24,8 +24,9 @@ where
exists(string n | p = f.getDependencyParameter(n) |
p.getName() != n and
exists(f.getDependencyParameter(p.getName())) and
msg = "This parameter is named '" + p.getName() + "', " +
"but actually refers to dependency '" + n + "'."
msg =
"This parameter is named '" + p.getName() + "', " + "but actually refers to dependency '" +
n + "'."
)
)
select p, msg

Просмотреть файл

@ -15,7 +15,8 @@ import javascript
from AngularJS::ServiceReference compile, SimpleParameter elem, CallExpr c
where
compile.getName() = "$compile" and
elem = any(AngularJS::CustomDirective d)
elem =
any(AngularJS::CustomDirective d)
.getALinkFunction()
.(AngularJS::LinkFunction)
.getElementParameter() and

Просмотреть файл

@ -130,7 +130,8 @@ where
kind = getServiceKind(request, name) and
exists(request.getAServiceDefinition(name)) and // ignore unknown/undefined services
not isCompatibleRequestedService(request, kind) and
compatibleWithString = concat(string compatibleKind |
compatibleWithString =
concat(string compatibleKind |
isCompatibleRequestedService(request, compatibleKind) and
not isWildcardKind(compatibleKind)
|

Просмотреть файл

@ -34,8 +34,9 @@ predicate isMissingParameter(AngularJS::InjectableFunction f, string msg, ASTNod
then dependenciesAreString = "dependency is"
else dependenciesAreString = "dependencies are"
) and
msg = "This function has " + paramCount + " " + parametersString + ", but " + injectionCount +
" " + dependenciesAreString + " injected into it."
msg =
"This function has " + paramCount + " " + parametersString + ", but " + injectionCount + " "
+ dependenciesAreString + " injected into it."
)
)
}

Просмотреть файл

@ -31,7 +31,8 @@ VarRef refInContainer(Variable var, RefKind kind, StmtContainer sc) {
* declaration of `var` (if `kind` is `Decl()`) in `sc`.
*/
VarRef firstRefInContainer(Variable var, RefKind kind, StmtContainer sc) {
result = min(refInContainer(var, kind, sc) as ref
result =
min(refInContainer(var, kind, sc) as ref
order by
ref.getLocation().getStartLine(), ref.getLocation().getStartColumn()
)
@ -52,7 +53,8 @@ VarRef refInTopLevel(Variable var, RefKind kind, TopLevel tl) {
* declaration of `var` (if `kind` is `Decl()`) in `tl`.
*/
VarRef firstRefInTopLevel(Variable var, RefKind kind, TopLevel tl) {
result = min(refInTopLevel(var, kind, tl) as ref
result =
min(refInTopLevel(var, kind, tl) as ref
order by
ref.getLocation().getStartLine(), ref.getLocation().getStartColumn()
)

Просмотреть файл

@ -57,7 +57,8 @@ GlobalVarAccess getAccessIn(GlobalVariable v, Function f) {
* Gets the (lexically) first access to variable `v` in function `f`.
*/
GlobalVarAccess getFirstAccessIn(GlobalVariable v, Function f) {
result = min(getAccessIn(v, f) as gva
result =
min(getAccessIn(v, f) as gva
order by
gva.getLocation().getStartLine(), gva.getLocation().getStartColumn()
)

Просмотреть файл

@ -1,7 +1,7 @@
/**
* @name Suspicious method name declaration
* @description A method declaration with a name that is a special keyword in another
* context is suspicious.
* @description A method declaration with a name that is a special keyword in another
* context is suspicious.
* @kind problem
* @problem.severity warning
* @id js/suspicious-method-name-declaration
@ -19,7 +19,7 @@ import javascript
predicate isSuspiciousMethodName(string name, ClassOrInterface container) {
name = "function"
or
// "constructor" is only suspicious outside a class.
// "constructor" is only suspicious outside a class.
name = "constructor" and not container instanceof ClassDefinition
or
// "new" is only suspicious inside a class.
@ -31,7 +31,6 @@ where
container.getLocation().getFile().getFileType().isTypeScript() and
container.getMember(name) = member and
isSuspiciousMethodName(name, container) and
// Cases to ignore.
not (
// Assume that a "new" method is intentional if the class has an explicit constructor.
@ -39,31 +38,34 @@ where
container instanceof ClassDefinition and
exists(ConstructorDeclaration constructor |
container.getMember("constructor") = constructor and
not constructor.isSynthetic()
)
not constructor.isSynthetic()
)
or
// Explicitly declared static methods are fine.
container instanceof ClassDefinition and
member.isStatic()
or
// Only looking for declared methods. Methods with a body are OK.
// Only looking for declared methods. Methods with a body are OK.
exists(member.getBody().getBody())
or
// The developer was not confused about "function" when there are other methods in the interface.
name = "function" and
name = "function" and
exists(MethodDeclaration other | other = container.getAMethod() |
other.getName() != "function" and
not other.(ConstructorDeclaration).isSynthetic()
)
)
and
) and
(
name = "constructor" and msg = "The member name 'constructor' does not declare a constructor in interfaces, but it does in classes."
name = "constructor" and
msg =
"The member name 'constructor' does not declare a constructor in interfaces, but it does in classes."
or
name = "new" and msg = "The member name 'new' does not declare a constructor, but 'constructor' does in class declarations."
name = "new" and
msg =
"The member name 'new' does not declare a constructor, but 'constructor' does in class declarations."
or
name = "function" and msg = "The member name 'function' does not declare a function, it declares a method named 'function'."
name = "function" and
msg =
"The member name 'function' does not declare a function, it declares a method named 'function'."
)
select member, msg

Просмотреть файл

@ -44,43 +44,39 @@ string getKind(MemberDeclaration m) {
* A call-signature that originates from a MethodSignature in the AST.
*/
private class MethodCallSig extends CallSignatureType {
string name;
MethodCallSig() {
exists(MethodSignature sig |
this = sig.getBody().getCallSignature() and
name = sig.getName()
)
}
/**
* Gets the name of any member that has this signature.
*/
string getName() {
result = name
}
string name;
MethodCallSig() {
exists(MethodSignature sig |
this = sig.getBody().getCallSignature() and
name = sig.getName()
)
}
/**
* Gets the name of any member that has this signature.
*/
string getName() { result = name }
}
/**
* Holds if the two call signatures could be overloads of each other and have the same parameter types.
*/
predicate matchingCallSignature(MethodCallSig method, MethodCallSig other) {
method.getName() = other.getName() and
method.getName() = other.getName() and
method.getNumOptionalParameter() = other.getNumOptionalParameter() and
method.getNumParameter() = other.getNumParameter() and
method.getNumRequiredParameter() = other.getNumRequiredParameter() and
// purposely not looking at number of type arguments.
method.getKind() = other.getKind() and
forall(int i | i in [0 .. -1 + method.getNumParameter()] |
// purposely not looking at number of type arguments.
method.getKind() = other.getKind() and
forall(int i | i in [0 .. -1 + method.getNumParameter()] |
method.getParameter(i) = other.getParameter(i) // This is sometimes imprecise, so it is still a good idea to compare type annotations.
) and
// shared type parameters are equal.
forall(int i | i in [0 .. -1 + min(int num | num = method.getNumTypeParameter() or num = other.getNumTypeParameter())] |
) and
// shared type parameters are equal.
forall(int i |
i in [0 .. -1 +
min(int num | num = method.getNumTypeParameter() or num = other.getNumTypeParameter())]
|
method.getTypeParameterBound(i) = other.getTypeParameterBound(i)
)
}
@ -89,7 +85,7 @@ predicate matchingCallSignature(MethodCallSig method, MethodCallSig other) {
* Gets which overload index the MethodSignature has among the overloads of the same name.
*/
int getOverloadIndex(MethodSignature sig) {
sig.getDeclaringType().getMethodOverload(sig.getName(), result) = sig
sig.getDeclaringType().getMethodOverload(sig.getName(), result) = sig
}
/**
@ -100,18 +96,14 @@ predicate signaturesMatch(MethodSignature method, MethodSignature other) {
method.getDeclaringType() = other.getDeclaringType() and
// same static modifier.
getKind(method) = getKind(other) and
// same name.
method.getName() = other.getName() and
// same number of parameters.
method.getBody().getNumParameter() = other.getBody().getNumParameter() and
// The types are compared in matchingCallSignature. This is sanity-check that the textual representation of the type-annotations are somewhat similar.
forall(int i | i in [0 .. -1 + method.getBody().getNumParameter()] |
getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i)
getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i)
) and
matchingCallSignature(method.getBody().getCallSignature(), other.getBody().getCallSignature())
}
@ -119,22 +111,19 @@ from ClassOrInterface decl, string name, MethodSignature previous, MethodSignatu
where
previous = decl.getMethod(name) and
unreachable = getOtherMatchingSignatures(previous) and
// If the method is part of inheritance between classes/interfaces, then there can sometimes be reasons for having this pattern.
not exists(decl.getASuperTypeDeclaration().getMethod(name)) and
not exists(ClassOrInterface sub |
not exists(decl.getASuperTypeDeclaration().getMethod(name)) and
not exists(ClassOrInterface sub |
decl = sub.getASuperTypeDeclaration() and
exists(sub.getMethod(name))
) and
// If a later method overload has more type parameters, then that overload can be selected by explicitly declaring the type arguments at the callsite.
// This comparison removes those cases.
unreachable.getBody().getNumTypeParameter() <= previous.getBody().getNumTypeParameter() and
// We always select the first of the overloaded methods.
not exists(MethodSignature later | later = getOtherMatchingSignatures(previous) |
getOverloadIndex(later) < getOverloadIndex(previous)
)
select unreachable,
"This overload of " + name + "() is unreachable, the $@ overload will always be selected.", previous, "previous"
"This overload of " + name + "() is unreachable, the $@ overload will always be selected.",
previous, "previous"

Просмотреть файл

@ -74,7 +74,8 @@ class CandidateVarAccess extends VarAccess {
* We use this to avoid duplicate alerts about the same underlying cyclic import.
*/
VarAccess getFirstCandidateAccess(ImportDeclaration decl) {
result = min(decl.getASpecifier().getLocal().getVariable().getAnAccess().(CandidateVarAccess) as p
result =
min(decl.getASpecifier().getLocal().getVariable().getAnAccess().(CandidateVarAccess) as p
order by
p.getFirstToken().getIndex()
)
@ -133,14 +134,15 @@ string pathToModule(Module source, Module destination, int steps) {
steps > 1 and
exists(Module next |
// Only extend the path to one of the potential successors, as we only need one example.
next = min(Module mod |
next =
min(Module mod |
isImportedAtRuntime(source, mod) and
numberOfStepsToModule(mod, destination, steps - 1)
|
mod order by mod.getName()
) and
result = repr(getARuntimeImport(source, next)) + " => " +
pathToModule(next, destination, steps - 1)
result =
repr(getARuntimeImport(source, next)) + " => " + pathToModule(next, destination, steps - 1)
)
)
}

Просмотреть файл

@ -16,7 +16,6 @@ import javascript
import ExprHasNoEffect
import semmle.javascript.RestrictedLocations
from Expr e
where hasNoEffect(e)
select e.(FirstLineOf), "This expression has no effect."

Просмотреть файл

@ -200,10 +200,12 @@ where
rightExprDescription = getDescription(right.asExpr(), "an expression") and
leftTypeCount = strictcount(left.getAType()) and
rightTypeCount = strictcount(right.getAType()) and
leftTypeDescription = getTypeDescription("is of type " + leftTypes,
"cannot be of type " + rightTypes, leftTypeCount, rightTypeCount) and
rightTypeDescription = getTypeDescription("of type " + rightTypes,
", which cannot be of type " + leftTypes, rightTypeCount, leftTypeCount)
leftTypeDescription =
getTypeDescription("is of type " + leftTypes, "cannot be of type " + rightTypes, leftTypeCount,
rightTypeCount) and
rightTypeDescription =
getTypeDescription("of type " + rightTypes, ", which cannot be of type " + leftTypes,
rightTypeCount, leftTypeCount)
select left,
leftExprDescription + " " + leftTypeDescription + ", but it is compared to $@ " +
rightTypeDescription + ".", right, rightExprDescription

Просмотреть файл

@ -23,48 +23,40 @@ Expr leftChild(Expr e) {
}
predicate isInConcat(Expr e) {
exists(ParExpr par | isInConcat(par) and par.getExpression() = e)
or
exists(AddExpr a | a.getAnOperand() = e)
exists(ParExpr par | isInConcat(par) and par.getExpression() = e)
or
exists(AddExpr a | a.getAnOperand() = e)
}
class ConcatenationLiteral extends Expr {
ConcatenationLiteral() {
(
this instanceof TemplateLiteral
this instanceof TemplateLiteral
or
this instanceof Literal
)
and isInConcat(this)
) and
isInConcat(this)
}
}
Expr getConcatChild(Expr e) {
result = rightChild(e) or
result = leftChild(e)
result = rightChild(e) or
result = leftChild(e)
}
Expr getConcatParent(Expr e) {
e = getConcatChild(result)
}
Expr getConcatParent(Expr e) { e = getConcatChild(result) }
predicate isWordLike(ConcatenationLiteral lit) {
lit.getStringValue().regexpMatch("(?i).*[a-z]{3,}.*")
lit.getStringValue().regexpMatch("(?i).*[a-z]{3,}.*")
}
class ConcatRoot extends AddExpr {
ConcatRoot() {
not isInConcat(this)
}
ConcatRoot() { not isInConcat(this) }
}
ConcatRoot getAddRoot(AddExpr e) {
result = getConcatParent*(e)
}
ConcatRoot getAddRoot(AddExpr e) { result = getConcatParent*(e) }
predicate hasWordLikeFragment(AddExpr e) {
isWordLike(getConcatChild*(getAddRoot(e)))
}
predicate hasWordLikeFragment(AddExpr e) { isWordLike(getConcatChild*(getAddRoot(e))) }
from AddExpr e, ConcatenationLiteral l, ConcatenationLiteral r, string word
where
@ -79,7 +71,6 @@ where
word = l.getStringValue().regexpCapture(".* (([-A-Za-z/'\\.:,]*[a-zA-Z]|[0-9]+)[\\.:,!?']*)", 1) and
r.getStringValue().regexpMatch("[a-zA-Z].*") and
not word.regexpMatch(".*[,\\.:].*[a-zA-Z].*[^a-zA-Z]") and
// There must be a constant-string in the concatenation that looks like a word.
hasWordLikeFragment(e)
select l, "This string appears to be missing a space after '" + word + "'."

Просмотреть файл

@ -91,7 +91,8 @@ private string replaceATypoAndLowerCase(Identifier wrong) {
idPart(wrong, wrongPart, offset)
|
normalized_typos(wrongPart, rightPart, _, _, _, _) and
rightName = wrong.getName().substring(0, offset) + rightPart +
rightName =
wrong.getName().substring(0, offset) + rightPart +
wrong.getName().suffix(offset + wrongPart.length()) and
result = rightName.toLowerCase()
)

Просмотреть файл

@ -36,7 +36,8 @@ private predicate isBoundInMethod(MethodDeclaration method) {
mod = "react-autobind"
|
thiz.flowsTo(DataFlow::moduleImport(mod).getACall().getArgument(0))
) or
)
or
// heuristic reflective binders
exists(DataFlow::CallNode binder, string calleeName |
(
@ -92,8 +93,8 @@ private DOM::AttributeDefinition getAnEventHandlerAttribute() {
from MethodDeclaration callback, DOM::AttributeDefinition attribute, ThisExpr unbound
where
attribute = getAnEventHandlerAttribute() and
attribute.getValueNode().analyze().getAValue().(AbstractFunction).getFunction() = callback
.getBody() and
attribute.getValueNode().analyze().getAValue().(AbstractFunction).getFunction() =
callback.getBody() and
unbound.getBinder() = callback.getBody() and
not isBoundInMethod(callback)
select attribute,

Просмотреть файл

@ -59,7 +59,8 @@ where
not isCallToFunction(cs) and
// conservatively only flag call sites where _all_ callees are illegal
forex(DataFlow::InvokeNode cs2, Function otherCallee |
cs2.getInvokeExpr() = cs.getInvokeExpr() and otherCallee = cs2.getACallee() |
cs2.getInvokeExpr() = cs.getInvokeExpr() and otherCallee = cs2.getACallee()
|
illegalInvocation(cs, otherCallee, _, _)
) and
// require that all callees are known

Просмотреть файл

@ -35,7 +35,8 @@ predicate guardsAgainstMissingNew(Function f) {
* `true` if `cs` is a `new` expression, and to `false` otherwise.
*/
Function getALikelyCallee(DataFlow::InvokeNode cs, boolean isNew) {
result = min(Function callee, int imprecision |
result =
min(Function callee, int imprecision |
callee = cs.getACallee(imprecision)
|
callee order by imprecision
@ -84,7 +85,8 @@ predicate whitelistedCall(DataFlow::CallNode call) {
* and start column.
*/
DataFlow::InvokeNode getFirstInvocation(Function f, boolean isNew) {
result = min(DataFlow::InvokeNode invk, string path, int line, int col |
result =
min(DataFlow::InvokeNode invk, string path, int line, int col |
f = getALikelyCallee(invk, isNew) and invk.hasLocationInfo(path, line, col, _, _)
|
invk order by path, line, col

Просмотреть файл

@ -14,7 +14,8 @@ import javascript
from File f, float n
where
n = avg(Function fun, int toAvg |
n =
avg(Function fun, int toAvg |
fun.getTopLevel().getFile() = f and toAvg = fun.getCyclomaticComplexity()
|
toAvg

Просмотреть файл

@ -16,7 +16,6 @@ import javascript
import semmle.javascript.security.performance.PolynomialReDoS::PolynomialReDoS
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This expensive $@ use depends on $@.",

Просмотреть файл

@ -292,9 +292,7 @@ class EdgeLabel extends TInputSymbol {
* Gets the state before matching `t`.
*/
pragma[inline]
State before(RegExpTerm t) {
result = Match(t, 0)
}
State before(RegExpTerm t) { result = Match(t, 0) }
/**
* Gets a state the NFA may be in after matching `t`.
@ -337,9 +335,7 @@ predicate delta(State q1, EdgeLabel lbl, State q2) {
)
)
or
exists(RegExpDot dot |
q1 = before(dot) and q2 = after(dot)
|
exists(RegExpDot dot | q1 = before(dot) and q2 = after(dot) |
if dot.getLiteral().isDotAll() then lbl = Any() else lbl = Dot()
)
or
@ -545,7 +541,8 @@ string intersect(InputSymbol c, InputSymbol d) {
* Gets a character matched by character class `cc`.
*/
string choose(RegExpCharacterClass cc) {
result = min(string c |
result =
min(string c |
exists(RegExpTerm child | child = cc.getAChild() |
c = child.(RegExpConstant).getValue() or
child.(RegExpCharacterRange).isRange(c, _)

Просмотреть файл

@ -14,6 +14,7 @@
import javascript
from RegExpCharEscape rece
where rece.toString() = "\\b"
and rece.isPartOfRegExpLiteral()
where
rece.toString() = "\\b" and
rece.isPartOfRegExpLiteral()
select rece, "Backspace escape in regular expression."

Просмотреть файл

@ -18,7 +18,8 @@ import javascript
* Indexing is 1-based.
*/
predicate constantInCharacterClass(RegExpCharacterClass recc, int i, RegExpConstant cc, string val) {
cc = rank[i](RegExpConstant cc2, int j |
cc =
rank[i](RegExpConstant cc2, int j |
cc2 = recc.getChild(j) and cc2.isCharacter() and cc2.getValue() = val
|
cc2 order by j

Просмотреть файл

@ -58,7 +58,8 @@ predicate regExpMatchesString(RegExpTerm t, string s) {
or
// sequences match the concatenation of their elements
exists(RegExpSequence seq | seq = t |
s = concat(int i, RegExpTerm child |
s =
concat(int i, RegExpTerm child |
child = seq.getChild(i)
|
any(string subs | regExpMatchesString(child, subs)) order by i

Просмотреть файл

@ -73,13 +73,9 @@ abstract class RegExpQuery extends DataFlow::CallNode {
class RegExpTestCall extends DataFlow::MethodCallNode, RegExpQuery {
DataFlow::RegExpCreationNode regexp;
RegExpTestCall() {
this = regexp.getAReference().getAMethodCall("test")
}
RegExpTestCall() { this = regexp.getAReference().getAMethodCall("test") }
override RegExpTerm getRegExp() {
result = regexp.getRoot()
}
override RegExpTerm getRegExp() { result = regexp.getRoot() }
}
/**
@ -93,9 +89,7 @@ class RegExpSearchCall extends DataFlow::MethodCallNode, RegExpQuery {
regexp.getAReference().flowsTo(getArgument(0))
}
override RegExpTerm getRegExp() {
result = regexp.getRoot()
}
override RegExpTerm getRegExp() { result = regexp.getRoot() }
}
/**
@ -116,10 +110,12 @@ where
(
call instanceof RegExpTestCall and
not isPossiblyAnchoredOnBothEnds(term) and
message = "This regular expression always matches when used in a test $@, as it can match an empty substring."
message =
"This regular expression always matches when used in a test $@, as it can match an empty substring."
or
call instanceof RegExpSearchCall and
not term.getAChild*() instanceof RegExpDollar and
message = "This regular expression always the matches at index 0 when used $@, as it matches the empty substring."
message =
"This regular expression always the matches at index 0 when used $@, as it matches the empty substring."
)
select term, message, call, "here"

Просмотреть файл

@ -2,6 +2,7 @@
* Provides predicates for reasoning about regular expressions
* that match URLs and hostname patterns.
*/
import javascript
/**
@ -39,9 +40,7 @@ predicate isDotLike(RegExpTerm term) {
predicate matchesBeginningOfString(RegExpTerm term) {
term.isRootTerm()
or
exists(RegExpTerm parent |
matchesBeginningOfString(parent)
|
exists(RegExpTerm parent | matchesBeginningOfString(parent) |
term = parent.(RegExpSequence).getChild(0)
or
parent.(RegExpSequence).getChild(0) instanceof RegExpCaret and
@ -60,7 +59,11 @@ predicate matchesBeginningOfString(RegExpTerm term) {
* `i` is bound to the index of the last child in the top-level domain part.
*/
predicate hasTopLevelDomainEnding(RegExpSequence seq, int i) {
seq.getChild(i).(RegExpConstant).getValue().regexpMatch("(?i)" + RegExpPatterns::commonTLD() + "(:\\d+)?([/?#].*)?") and
seq
.getChild(i)
.(RegExpConstant)
.getValue()
.regexpMatch("(?i)" + RegExpPatterns::commonTLD() + "(:\\d+)?([/?#].*)?") and
isDotLike(seq.getChild(i - 1)) and
not (i = 1 and matchesBeginningOfString(seq))
}
@ -69,9 +72,7 @@ predicate hasTopLevelDomainEnding(RegExpSequence seq, int i) {
* Holds if the given regular expression term contains top-level domain preceded by a dot,
* such as `.com`.
*/
predicate hasTopLevelDomainEnding(RegExpSequence seq) {
hasTopLevelDomainEnding(seq, _)
}
predicate hasTopLevelDomainEnding(RegExpSequence seq) { hasTopLevelDomainEnding(seq, _) }
/**
* Holds if `term` will always match a hostname, that is, all disjunctions contain

Просмотреть файл

@ -61,9 +61,12 @@ predicate isIncompleteHostNameRegExpPattern(RegExpTerm regexp, RegExpSequence se
unescapedDot = seq.getChild([0 .. i - 1]).getAChild*() and
unescapedDot != seq.getChild(i - 1) and // Should not be the '.' immediately before the TLD
not hasConsecutiveDots(unescapedDot.getParent()) and
hostname = seq.getChild(i - 2).getRawValue() + seq.getChild(i - 1).getRawValue() + seq.getChild(i).getRawValue()
hostname =
seq.getChild(i - 2).getRawValue() + seq.getChild(i - 1).getRawValue() +
seq.getChild(i).getRawValue()
|
if unescapedDot.getParent() instanceof RegExpQuantifier then (
if unescapedDot.getParent() instanceof RegExpQuantifier
then
// `.*\.example.com` can match `evil.com/?x=.example.com`
//
// This problem only occurs when the pattern is applied against a full URL, not just a hostname/origin.
@ -73,16 +76,20 @@ predicate isIncompleteHostNameRegExpPattern(RegExpTerm regexp, RegExpSequence se
seq.getChild(0) instanceof RegExpCaret and
not seq.getAChild() instanceof RegExpDollar and
seq.getChild([i .. i + 1]).(RegExpConstant).getValue().regexpMatch(".*[/?#].*") and
msg = "has an unrestricted wildcard '" +
unescapedDot.getParent().(RegExpQuantifier).getRawValue() +
"' which may cause '" + hostname + "' to be matched anywhere in the URL, outside the hostname."
) else (
msg = "has an unescaped '.' before '" + hostname + "', so it might match more hosts than expected."
)
msg =
"has an unrestricted wildcard '" + unescapedDot.getParent().(RegExpQuantifier).getRawValue()
+ "' which may cause '" + hostname +
"' to be matched anywhere in the URL, outside the hostname."
else
msg =
"has an unescaped '.' before '" + hostname +
"', so it might match more hosts than expected."
)
}
from RegExpPatternSource re, RegExpTerm regexp, RegExpSequence hostSequence, string msg, string kind, DataFlow::Node aux
from
RegExpPatternSource re, RegExpTerm regexp, RegExpSequence hostSequence, string msg, string kind,
DataFlow::Node aux
where
regexp = re.getRegExpTerm() and
isIncompleteHostNameRegExpPattern(regexp, hostSequence, msg) and
@ -96,5 +103,4 @@ where
)
) and
not CharacterEscapes::hasALikelyRegExpPatternMistake(re)
select hostSequence,
"This " + kind + " " + msg, aux, "here"
select hostSequence, "This " + kind + " " + msg, aux, "here"

Просмотреть файл

@ -20,9 +20,7 @@ class DangerousScheme extends string {
}
/** Gets a data-flow node that checks `nd` against the given `scheme`. */
DataFlow::Node schemeCheck(
DataFlow::Node nd, DangerousScheme scheme
) {
DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) {
// check of the form `nd.startsWith(scheme)`
exists(StringOps::StartsWith sw | sw = result |
sw.getBaseString() = nd and

Просмотреть файл

@ -46,9 +46,7 @@ predicate isInteriorAnchor(RegExpAnchor term) {
* Holds if `term` contains an anchor that is not the first or last node
* in its tree, such as `(foo|bar$|baz)`.
*/
predicate containsInteriorAnchor(RegExpTerm term) {
isInteriorAnchor(term.getAChild*())
}
predicate containsInteriorAnchor(RegExpTerm term) { isInteriorAnchor(term.getAChild*()) }
/**
* Holds if `term` starts with a word boundary or lookbehind assertion,
@ -78,9 +76,7 @@ predicate containsTrailingPseudoAnchor(RegExpSequence term) {
* Holds if `term` is an empty sequence, usually arising from
* literals with a trailing alternative such as `foo|`.
*/
predicate isEmpty(RegExpSequence term) {
term.getNumChild() = 0
}
predicate isEmpty(RegExpSequence term) { term.getNumChild() = 0 }
/**
* Holds if `term` contains a letter constant.
@ -131,14 +127,14 @@ predicate hasMisleadingAnchorPrecedence(RegExpPatternSource src, string msg) {
(
anchoredTerm = root.getChild(0) and
anchoredTerm.getChild(0) instanceof RegExpCaret and
not containsLeadingPseudoAnchor(root.getChild([ 1 .. root.getNumChild() - 1 ])) and
containsLetters(root.getChild([ 1 .. root.getNumChild() - 1 ])) and
not containsLeadingPseudoAnchor(root.getChild([1 .. root.getNumChild() - 1])) and
containsLetters(root.getChild([1 .. root.getNumChild() - 1])) and
direction = "beginning"
or
anchoredTerm = root.getLastChild() and
anchoredTerm.getLastChild() instanceof RegExpDollar and
not containsTrailingPseudoAnchor(root.getChild([ 0 .. root.getNumChild() - 2 ])) and
containsLetters(root.getChild([ 0 .. root.getNumChild() - 2 ])) and
not containsTrailingPseudoAnchor(root.getChild([0 .. root.getNumChild() - 2])) and
containsLetters(root.getChild([0 .. root.getNumChild() - 2])) and
direction = "end"
) and
// is not used for replace
@ -146,8 +142,10 @@ predicate hasMisleadingAnchorPrecedence(RegExpPatternSource src, string msg) {
replace.getMethodName() = "replace" and
src.getARegExpObject().flowsTo(replace.getArgument(0))
) and
msg = "Misleading operator precedence. The subexpression '" + anchoredTerm.getRawValue() +
"' is anchored at the " + direction + ", but the other parts of this regular expression are not"
msg =
"Misleading operator precedence. The subexpression '" + anchoredTerm.getRawValue() +
"' is anchored at the " + direction +
", but the other parts of this regular expression are not"
)
}
@ -181,7 +179,8 @@ predicate isSemiAnchoredHostnameRegExp(RegExpPatternSource src, string msg) {
hasTopLevelDomainEnding(tld, i) and
isFinalRegExpTerm(tld.getChild(i)) and // nothing is matched after the TLD
tld.getChild(0) instanceof RegExpCaret and
msg = "This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end."
msg =
"This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end."
)
}
@ -214,7 +213,8 @@ predicate isUnanchoredHostnameRegExp(RegExpPatternSource src, string msg) {
name = "match" and exists(mcn.getAPropertyRead())
)
) and
msg = "When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it."
msg =
"When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it."
)
}

Просмотреть файл

@ -105,13 +105,9 @@ class RegExpPatternMistake extends TRegExpPatternMistake {
*/
class IdentityEscapeInStringMistake extends RegExpPatternMistake, TIdentityEscapeInStringMistake {
RegExpPatternSource src;
string char;
string mistake;
int index;
ASTNode rawStringNode;
IdentityEscapeInStringMistake() {
@ -130,19 +126,19 @@ class IdentityEscapeInStringMistake extends RegExpPatternMistake, TIdentityEscap
}
/**
* A backspace as '\b' in a regular expression string, indicating
* programmer intent to use the word-boundary assertion '\b'.
*/
* A backspace as '\b' in a regular expression string, indicating
* programmer intent to use the word-boundary assertion '\b'.
*/
class BackspaceInStringMistake extends RegExpPatternMistake, TBackspaceInStringMistake {
RegExpPatternSource src;
int index;
ASTNode rawStringNode;
BackspaceInStringMistake() { this = TBackspaceInStringMistake(src, rawStringNode, index) }
override string getMessage() { result = "'\\b' is a backspace, and not a word-boundary assertion" }
override string getMessage() {
result = "'\\b' is a backspace, and not a word-boundary assertion"
}
override int getIndex() { result = index }

Просмотреть файл

@ -16,11 +16,16 @@ import javascript
import semmle.javascript.security.dataflow.CommandInjection::CommandInjection
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node highlight, Source sourceNode
from
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node highlight,
Source sourceNode
where
cfg.hasFlowPath(source, sink) and
if cfg.isSinkWithHighlight(sink.getNode(), _)
then cfg.isSinkWithHighlight(sink.getNode(), highlight)
else highlight = sink.getNode() and
(
if cfg.isSinkWithHighlight(sink.getNode(), _)
then cfg.isSinkWithHighlight(sink.getNode(), highlight)
else highlight = sink.getNode()
) and
sourceNode = source.getNode()
select highlight, source, sink, "This command depends on $@.", sourceNode, sourceNode.getSourceType()
select highlight, source, sink, "This command depends on $@.", sourceNode,
sourceNode.getSourceType()

Просмотреть файл

@ -15,10 +15,8 @@ import javascript
import semmle.javascript.security.dataflow.ExceptionXss::ExceptionXss
import DataFlow::PathGraph
from
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where
cfg.hasFlowPath(source, sink)
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
sink.getNode().(Xss::Shared::Sink).getVulnerabilityKind() + " vulnerability due to $@.", source.getNode(),
"user-provided value"
sink.getNode().(Xss::Shared::Sink).getVulnerabilityKind() + " vulnerability due to $@.",
source.getNode(), "user-provided value"

Просмотреть файл

@ -44,23 +44,17 @@ predicate escapingScheme(string metachar, string regex) {
* A call to `String.prototype.replace` that replaces all instances of a pattern.
*/
class Replacement extends StringReplaceCall {
Replacement() {
isGlobal()
}
Replacement() { isGlobal() }
/**
* Gets the input of this replacement.
*/
DataFlow::Node getInput() {
result = this.getReceiver()
}
DataFlow::Node getInput() { result = this.getReceiver() }
/**
* Gets the output of this replacement.
*/
DataFlow::SourceNode getOutput() {
result = this
}
DataFlow::SourceNode getOutput() { result = this }
/**
* Holds if this replacement escapes `char` using `metachar`.
@ -93,9 +87,7 @@ class Replacement extends StringReplaceCall {
/**
* Gets the previous replacement in this chain of replacements.
*/
Replacement getPreviousReplacement() {
result.getOutput() = getASimplePredecessor*(getInput())
}
Replacement getPreviousReplacement() { result.getOutput() = getASimplePredecessor*(getInput()) }
/**
* Gets an earlier replacement in this chain of replacements that

Просмотреть файл

@ -44,9 +44,7 @@ predicate isSimpleCharacterClass(RegExpCharacterClass t) {
}
/** Holds if `t` is an alternation of simple terms. */
predicate isSimpleAlt(RegExpAlt t) {
forall(RegExpTerm ch | ch = t.getAChild() | isSimple(ch))
}
predicate isSimpleAlt(RegExpAlt t) { forall(RegExpTerm ch | ch = t.getAChild() | isSimple(ch)) }
/**
* Holds if `mce` is of the form `x.replace(re, new)`, where `re` is a global

Просмотреть файл

@ -13,26 +13,20 @@
import javascript
/** Gets a property name of `req` which refers to data usually derived from cookie data. */
string cookieProperty() {
result = "session" or result = "cookies" or result = "user"
}
string cookieProperty() { result = "session" or result = "cookies" or result = "user" }
/** Gets a data flow node that flows to the base of an access to `cookies`, `session`, or `user`. */
private DataFlow::SourceNode nodeLeadingToCookieAccess(DataFlow::TypeBackTracker t) {
t.start() and
exists(DataFlow::PropRead value |
value = result.getAPropertyRead(cookieProperty()).getAPropertyRead() and
// Ignore accesses to values that are part of a CSRF or captcha check
not value.getPropertyName().regexpMatch("(?i).*(csrf|xsrf|captcha).*") and
// Ignore calls like `req.session.save()`
not value = any(DataFlow::InvokeNode call).getCalleeNode()
)
or
exists(DataFlow::TypeBackTracker t2 |
result = nodeLeadingToCookieAccess(t2).backtrack(t2, t)
)
exists(DataFlow::TypeBackTracker t2 | result = nodeLeadingToCookieAccess(t2).backtrack(t2, t))
}
/** Gets a data flow node that flows to the base of an access to `cookies`, `session`, or `user`. */
@ -52,9 +46,7 @@ private DataFlow::SourceNode getARouteUsingCookies(DataFlow::TypeTracker t) {
t.start() and
isRouteHandlerUsingCookies(result)
or
exists(DataFlow::TypeTracker t2 |
result = getARouteUsingCookies(t2).track(t2, t)
)
exists(DataFlow::TypeTracker t2 | result = getARouteUsingCookies(t2).track(t2, t))
}
/** Gets a data flow node referring to a route handler that uses cookies. */
@ -113,7 +105,6 @@ from
where
router = setup.getRouter() and
handler = setup.getARouteHandlerExpr() and
// Require that the handler uses cookies and has cookie middleware.
//
// In practice, handlers that use cookies always have the cookie middleware or
@ -122,10 +113,8 @@ where
// don't trust it to detect the presence of CSRF middleware either.
getARouteUsingCookies().flowsToExpr(handler) and
hasCookieMiddleware(handler, cookie) and
// Only flag the cookie parser registered first.
not hasCookieMiddleware(cookie, _) and
not hasCsrfMiddleware(handler) and
// Only warn for the last handler in a chain.
handler.isLastHandler() and

Просмотреть файл

@ -1,7 +1,7 @@
/**
* @name Prototype pollution in utility function
* @description Recursively copying properties between objects may cause
accidental modification of a built-in prototype object.
* accidental modification of a built-in prototype object.
* @kind path-problem
* @problem.severity warning
* @precision high
@ -30,9 +30,7 @@ predicate arePropertiesEnumerated(DataFlow::SourceNode node) {
predicate isEnumeratedPropName(Node node) {
node instanceof EnumeratedPropName
or
exists(Node pred |
isEnumeratedPropName(pred)
|
exists(Node pred | isEnumeratedPropName(pred) |
node = pred.getASuccessor()
or
argumentPassingStep(_, pred, _, node)
@ -54,7 +52,6 @@ predicate isPotentiallyObjectPrototype(SourceNode node) {
exists(Node base, Node key |
dynamicPropReadStep(base, key, node) and
isEnumeratedPropName(key) and
// Ignore cases where the properties of `base` are enumerated, to avoid FPs
// where the key came from that enumeration (and thus will not return Object.prototype).
// For example, `src[key]` in `for (let key in src) { ... src[key] ... }` will generally
@ -62,9 +59,7 @@ predicate isPotentiallyObjectPrototype(SourceNode node) {
not arePropertiesEnumerated(base.getALocalSource())
)
or
exists(Node use |
isPotentiallyObjectPrototype(use.getALocalSource())
|
exists(Node use | isPotentiallyObjectPrototype(use.getALocalSource()) |
argumentPassingStep(_, use, _, node)
)
}
@ -87,7 +82,6 @@ predicate dynamicPropWrite(DataFlow::Node base, DataFlow::Node prop, DataFlow::N
rhs = write.getRhs().flow() and
not exists(prop.getStringValue()) and
not arePropertiesEnumerated(base.getALocalSource()) and
// Prune writes that are unlikely to modify Object.prototype.
// This is mainly for performance, but may block certain results due to
// not tracking out of function returns and into callbacks.
@ -435,9 +429,7 @@ private DataFlow::SourceNode getANodeLeadingToBase(DataFlow::TypeBackTracker t,
isPrototypePollutingAssignment(base, _, _, _) and
result = base.getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 |
result = getANodeLeadingToBase(t2, base).backtrack(t2, t)
)
exists(DataFlow::TypeBackTracker t2 | result = getANodeLeadingToBase(t2, base).backtrack(t2, t))
}
/**

Просмотреть файл

@ -14,8 +14,9 @@ import PortalExitSource
import PortalEntrySink
from
TaintTracking::Configuration cfg, DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink, Portal p1,
Portal p2, DataFlow::FlowLabel lbl1, DataFlow::FlowLabel lbl2, DataFlow::MidPathNode last
TaintTracking::Configuration cfg, DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink,
Portal p1, Portal p2, DataFlow::FlowLabel lbl1, DataFlow::FlowLabel lbl2,
DataFlow::MidPathNode last
where
cfg = source.getConfiguration() and
last = source.getASuccessor*() and

Просмотреть файл

@ -11,7 +11,8 @@ import Configurations
import PortalExitSource
import SinkFromAnnotation
from DataFlow::Configuration cfg, DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink,
from
DataFlow::Configuration cfg, DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink,
Portal p, DataFlow::MidPathNode last
where
cfg = source.getConfiguration() and

Просмотреть файл

@ -11,7 +11,8 @@ import Configurations
import PortalEntrySink
import SourceFromAnnotation
from DataFlow::Configuration cfg, DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink,
from
DataFlow::Configuration cfg, DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink,
Portal p, DataFlow::MidPathNode last
where
cfg = source.getConfiguration() and

Просмотреть файл

@ -127,7 +127,8 @@ class AdditionalStepSpec extends ExternalData {
exists(string config |
if getField(4) = "" then config = "any configuration" else config = getConfiguration()
|
result = "edge from " + getStartPortal() + " to " + getEndPortal() + ", transforming " +
result =
"edge from " + getStartPortal() + " to " + getEndPortal() + ", transforming " +
getStartFlowLabel() + " into " + getEndFlowLabel() + " for " + config
)
}

Просмотреть файл

@ -13,7 +13,7 @@ import javascript
import Expressions.ExprHasNoEffect
DataFlow::SourceNode callsArray(DataFlow::TypeBackTracker t, DataFlow::MethodCallNode call) {
isIgnoredPureArrayCall(call) and
isIgnoredPureArrayCall(call) and
t.start() and
result = call.getReceiver().getALocalSource()
or
@ -39,7 +39,7 @@ predicate isIgnoredPureArrayCall(DataFlow::MethodCallNode call) {
}
from DataFlow::MethodCallNode call
where
where
callsArray(call) instanceof DataFlow::ArrayCreationNode and
not call.getReceiver().asExpr().(ArrayExpr).getSize() = 0
select call, "Result from call to " + call.getMethodName() + " ignored."

Просмотреть файл

@ -32,7 +32,8 @@ class ValueReturn extends ReturnStmt {
/** Gets the lexically first explicit return statement in function `f`. */
ValueReturn getFirstExplicitReturn(Function f) {
result = min(ValueReturn ret |
result =
min(ValueReturn ret |
ret.getContainer() = f
|
ret order by ret.getLocation().getStartLine(), ret.getLocation().getStartColumn()

Просмотреть файл

@ -21,40 +21,41 @@ predicate returnsVoid(Function f) {
}
predicate isStub(Function f) {
f.getBody().(BlockStmt).getNumChild() = 0
or
f instanceof ExternalDecl
f.getBody().(BlockStmt).getNumChild() = 0
or
f instanceof ExternalDecl
}
/**
* Holds if `e` is in a syntactic context where it likely is fine that the value of `e` comes from a call to a returnless function.
*/
predicate benignContext(Expr e) {
inVoidContext(e) or
inVoidContext(e)
or
// A return statement is often used to just end the function.
e = any(Function f).getBody()
or
e = any(ReturnStmt r).getExpr()
or
exists(ConditionalExpr cond | cond.getABranch() = e and benignContext(cond))
or
exists(LogicalBinaryExpr bin | bin.getAnOperand() = e and benignContext(bin))
or
exists(ConditionalExpr cond | cond.getABranch() = e and benignContext(cond))
or
exists(LogicalBinaryExpr bin | bin.getAnOperand() = e and benignContext(bin))
or
exists(Expr parent | parent.getUnderlyingValue() = e and benignContext(parent))
or
or
any(VoidExpr voidExpr).getOperand() = e
or
// weeds out calls inside HTML-attributes.
e.getParent().(ExprStmt).getParent() instanceof CodeInAttribute or
e.getParent().(ExprStmt).getParent() instanceof CodeInAttribute
or
// and JSX-attributes.
e = any(JSXAttribute attr).getValue() or
exists(AwaitExpr await | await.getOperand() = e and benignContext(await))
e = any(JSXAttribute attr).getValue()
or
exists(AwaitExpr await | await.getOperand() = e and benignContext(await))
or
// Avoid double reporting with js/trivial-conditional
isExplicitConditional(_, e)
or
or
// Avoid double reporting with js/comparison-between-incompatible-types
any(Comparison binOp).getAnOperand() = e
or
@ -62,12 +63,14 @@ predicate benignContext(Expr e) {
any(PropAccess ac).getBase() = e
or
// Avoid double-reporting with js/unused-local-variable
exists(VariableDeclarator v | v.getInit() = e and v.getBindingPattern().getVariable() instanceof UnusedLocal)
exists(VariableDeclarator v |
v.getInit() = e and v.getBindingPattern().getVariable() instanceof UnusedLocal
)
or
// Avoid double reporting with js/call-to-non-callable
any(InvokeExpr invoke).getCallee() = e
or
// arguments to Promise.resolve (and promise library variants) are benign.
// arguments to Promise.resolve (and promise library variants) are benign.
e = any(PromiseCreationCall promise).getValue().asExpr()
}
@ -86,15 +89,13 @@ predicate alwaysThrows(Function f) {
/**
* Holds if the last statement in the function is flagged by the js/useless-expression query.
*/
predicate lastStatementHasNoEffect(Function f) {
hasNoEffect(f.getExit().getAPredecessor())
}
predicate lastStatementHasNoEffect(Function f) { hasNoEffect(f.getExit().getAPredecessor()) }
/**
* Holds if `func` is a callee of `call`, and all possible callees of `call` never return a value.
*/
predicate callToVoidFunction(DataFlow::CallNode call, Function func) {
not call.isIncomplete() and
not call.isIncomplete() and
func = call.getACallee() and
forall(Function f | f = call.getACallee() |
returnsVoid(f) and not isStub(f) and not alwaysThrows(f)
@ -122,22 +123,20 @@ predicate hasNonVoidCallbackMethod(string name) {
DataFlow::SourceNode array(DataFlow::TypeTracker t) {
t.start() and result instanceof DataFlow::ArrayCreationNode
or
exists (DataFlow::TypeTracker t2 |
result = array(t2).track(t2, t)
)
exists(DataFlow::TypeTracker t2 | result = array(t2).track(t2, t))
}
DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) }
/**
* Holds if `call` is an Array or Lodash method accepting a callback `func`,
* where the `call` expects a callback that returns an expression,
* but `func` does not return a value.
* where the `call` expects a callback that returns an expression,
* but `func` does not return a value.
*/
predicate voidArrayCallback(DataFlow::CallNode call, Function func) {
hasNonVoidCallbackMethod(call.getCalleeName()) and
exists(int index |
index = min(int i | exists(call.getCallback(i))) and
exists(int index |
index = min(int i | exists(call.getCallback(i))) and
func = call.getCallback(index).getFunction()
) and
returnsVoid(func) and
@ -151,26 +150,23 @@ predicate voidArrayCallback(DataFlow::CallNode call, Function func) {
}
predicate hasNonVoidReturnType(Function f) {
exists(TypeAnnotation type | type = f.getReturnTypeAnnotation() |
not type.isVoid()
)
exists(TypeAnnotation type | type = f.getReturnTypeAnnotation() | not type.isVoid())
}
/**
* Provides classes for working with various Deferred implementations.
* It is a heuristic. The heuristic assume that a class is a promise defintion
* Provides classes for working with various Deferred implementations.
* It is a heuristic. The heuristic assume that a class is a promise defintion
* if the class is called "Deferred" and the method `resolve` is called on an instance.
*
* Removes some false positives in the js/use-of-returnless-function query.
*
* Removes some false positives in the js/use-of-returnless-function query.
*/
module Deferred {
/**
* An instance of a `Deferred` class.
* An instance of a `Deferred` class.
* For example the result from `new Deferred()` or `new $.Deferred()`.
*/
class DeferredInstance extends DataFlow::NewNode {
// Describes both `new Deferred()`, `new $.Deferred` and other variants.
// Describes both `new Deferred()`, `new $.Deferred` and other variants.
DeferredInstance() { this.getCalleeName() = "Deferred" }
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
@ -179,7 +175,7 @@ module Deferred {
or
exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t))
}
DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) }
}
@ -188,7 +184,7 @@ module Deferred {
*/
private class DeferredPromiseDefinition extends PromiseDefinition, DeferredInstance {
DeferredPromiseDefinition() {
// hardening of the "Deferred" heuristic: a method call to `resolve`.
// hardening of the "Deferred" heuristic: a method call to `resolve`.
exists(ref().getAMethodCall("resolve"))
}
@ -210,12 +206,14 @@ module Deferred {
from DataFlow::CallNode call, Function func, string name, string msg
where
(
callToVoidFunction(call, func) and
callToVoidFunction(call, func) and
msg = "the $@ does not return anything, yet the return value is used." and
name = func.describe()
or
voidArrayCallback(call, func) and
msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + " is used." and
voidArrayCallback(call, func) and
msg =
"the $@ does not return anything, yet the return value from the call to " +
call.getCalleeName() + " is used." and
name = "callback function"
) and
not benignContext(call.getEnclosingExpr()) and
@ -224,5 +222,4 @@ where
not oneshotClosure(call) and
not hasNonVoidReturnType(func) and
not call.getEnclosingExpr() instanceof SuperCall
select
call, msg, func, name
select call, msg, func, name

Просмотреть файл

@ -1,6 +1,6 @@
/**
* Provides predicates for working with useless conditionals.
*/
/**
* Provides predicates for working with useless conditionals.
*/
import javascript
@ -18,4 +18,4 @@ predicate isExplicitConditional(ASTNode cond, Expr e) {
or
isExplicitConditional(_, cond) and
e = cond.(Expr).getUnderlyingValue().(LogicalBinaryExpr).getAnOperand()
}
}

Просмотреть файл

@ -266,7 +266,8 @@ predicate similarLines(File f, int line) {
}
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines = strictsum(SimilarBlock b, int toSum |
lines =
strictsum(SimilarBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
@ -278,7 +279,8 @@ pragma[noopt]
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
exists(int coveredApprox |
coveredApprox = strictsum(int num |
coveredApprox =
strictsum(int num |
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
@ -301,7 +303,8 @@ predicate duplicateLines(File f, int line) {
}
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines = strictsum(DuplicateBlock b, int toSum |
lines =
strictsum(DuplicateBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
@ -313,7 +316,8 @@ pragma[noopt]
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
exists(int coveredApprox |
coveredApprox = strictsum(int num |
coveredApprox =
strictsum(int num |
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and

5
javascript/ql/src/external/DefectFilter.qll поставляемый
Просмотреть файл

@ -48,7 +48,8 @@ class DefectResult extends int {
/** Gets the URL corresponding to the location of this query result. */
string getURL() {
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
+ ":" + getEndLine() + ":" + getEndColumn()
result =
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
getEndLine() + ":" + getEndColumn()
}
}

5
javascript/ql/src/external/MetricFilter.qll поставляемый
Просмотреть файл

@ -66,7 +66,8 @@ class MetricResult extends int {
/** Gets the URL corresponding to the location of this query result. */
string getURL() {
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
+ ":" + getEndLine() + ":" + getEndColumn()
result =
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
getEndLine() + ":" + getEndColumn()
}
}

Просмотреть файл

@ -86,9 +86,7 @@ SourceNode nodeLeadingToInvocation() {
* Holds if there is a call edge `invoke -> f` between a relevant invocation
* and a relevant function.
*/
predicate relevantCall(RelevantInvoke invoke, RelevantFunction f) {
FlowSteps::calls(invoke, f)
}
predicate relevantCall(RelevantInvoke invoke, RelevantFunction f) { FlowSteps::calls(invoke, f) }
/**
* A call site that can be resolved to a function in the same project.
@ -105,9 +103,7 @@ class ResolvableCall extends RelevantInvoke {
* A call site that could not be resolved.
*/
class UnresolvableCall extends RelevantInvoke {
UnresolvableCall() {
not this instanceof ResolvableCall
}
UnresolvableCall() { not this instanceof ResolvableCall }
}
/**

Просмотреть файл

@ -11,8 +11,6 @@
import javascript
import CallGraphQuality
Import unresolvableImport() {
not exists(result.getImportedModule())
}
Import unresolvableImport() { not exists(result.getImportedModule()) }
select projectRoot(), count(unresolvableImport())

Просмотреть файл

@ -12,7 +12,8 @@ import javascript
import semmle.javascript.meta.ExtractionMetrics::ExtractionMetrics
from File f, string cause
where not extraction_data(f, _, _, _) and cause = "No extraction_data for this file"
or
not extraction_time(f, _,_, _) and cause = "No extraction_time for this file"
select f, cause
where
not extraction_data(f, _, _, _) and cause = "No extraction_data for this file"
or
not extraction_time(f, _, _, _) and cause = "No extraction_time for this file"
select f, cause

Просмотреть файл

@ -9,4 +9,5 @@
import semmle.javascript.meta.ExtractionMetrics::ExtractionMetrics
from PhaseName phaseName
select phaseName, Aggregated::getCpuTime(phaseName) as CPU_NANO, Aggregated::getWallclockTime(phaseName) as WALLCLOCK_NANO
select phaseName, Aggregated::getCpuTime(phaseName) as CPU_NANO,
Aggregated::getWallclockTime(phaseName) as WALLCLOCK_NANO

Просмотреть файл

@ -235,7 +235,8 @@ class BasicBlock extends @cfg_node, Locatable {
*/
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
defAt(i, v, d) and
result = min(int j |
result =
min(int j |
(defAt(j, v, _) or useAt(j, v, _) or j = length()) and
j > i
)

Просмотреть файл

@ -57,7 +57,8 @@ module CharacterEscapes {
hasRawStringAndQuote(n, delim, rawStringNode, raw) and
if rawStringNode instanceof RegExpLiteral
then
additionalEscapeChars = Sets::regexpMetaChars() + Sets::regexpAssertionChars() + Sets::regexpCharClassChars() +
additionalEscapeChars =
Sets::regexpMetaChars() + Sets::regexpAssertionChars() + Sets::regexpCharClassChars() +
Sets::regexpBackreferenceChars()
else additionalEscapeChars = "b"
|

Просмотреть файл

@ -123,13 +123,14 @@ class ClassOrInterface extends @classorinterface, TypeParameterized {
* Anonymous classes and interfaces do not have a canonical name.
*/
TypeName getTypeName() { result.getADefinition() = this }
/**
* Gets the ClassOrInterface corresponding to either a super type or an implemented interface.
*/
ClassOrInterface getASuperTypeDeclaration() {
this.getSuperClass().(VarAccess).getVariable().getADeclaration() = result.getIdentifier() or
this.getASuperInterface().(LocalTypeAccess).getLocalTypeName().getADeclaration() = result.getIdentifier()
this.getASuperInterface().(LocalTypeAccess).getLocalTypeName().getADeclaration() =
result.getIdentifier()
}
}
@ -334,11 +335,8 @@ class ClassExpr extends @classexpr, ClassDefinition, Expr {
else
if exists(getClassInitializedMember())
then
result = min(ClassInitializedMember m |
m = getClassInitializedMember()
|
m order by m.getIndex()
)
result =
min(ClassInitializedMember m | m = getClassInitializedMember() | m order by m.getIndex())
else result = this
}
@ -688,7 +686,8 @@ class MethodDeclaration extends MemberDeclaration {
*/
int getOverloadIndex() {
exists(ClassOrInterface type, string name |
this = rank[result + 1](MethodDeclaration method, int i |
this =
rank[result + 1](MethodDeclaration method, int i |
methodDeclaredInType(type, name, i, method)
|
method order by i
@ -696,7 +695,8 @@ class MethodDeclaration extends MemberDeclaration {
)
or
exists(ClassDefinition type |
this = rank[result + 1](ConstructorDeclaration ctor, int i |
this =
rank[result + 1](ConstructorDeclaration ctor, int i |
ctor = type.getMemberByIndex(i)
|
ctor order by i
@ -1156,7 +1156,8 @@ class FunctionCallSignature extends @function_call_signature, CallSignature {
/** Gets the index of this function call signature among the function call signatures in the enclosing type. */
int getOverloadIndex() {
exists(ClassOrInterface type | type = getDeclaringType() |
this = rank[result + 1](FunctionCallSignature sig, int i |
this =
rank[result + 1](FunctionCallSignature sig, int i |
sig = type.getMemberByIndex(i)
|
sig order by i
@ -1186,7 +1187,8 @@ class ConstructorCallSignature extends @constructor_call_signature, CallSignatur
/** Gets the index of this constructor call signature among the constructor call signatures in the enclosing type. */
int getOverloadIndex() {
exists(ClassOrInterface type | type = getDeclaringType() |
this = rank[result + 1](ConstructorCallSignature sig, int i |
this =
rank[result + 1](ConstructorCallSignature sig, int i |
sig = type.getMemberByIndex(i)
|
sig order by i

Просмотреть файл

@ -284,7 +284,8 @@ private SsaDefinition getAPseudoDefinitionInput(SsaDefinition nd) {
*/
private int nextDefAfter(BasicBlock bb, Variable v, int i, VarDef d) {
bb.defAt(i, v, d) and
result = min(int jj |
result =
min(int jj |
(bb.defAt(jj, v, _) or jj = bb.length()) and
jj > i
)

Просмотреть файл

@ -78,9 +78,7 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration {
}
/** Holds if this is declared with the `type` keyword, so it only imports types. */
predicate isTypeOnly() {
hasTypeKeyword(this)
}
predicate isTypeOnly() { hasTypeKeyword(this) }
override predicate isAmbient() {
Stmt.super.isAmbient() or
@ -268,9 +266,7 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration {
abstract DataFlow::Node getSourceNode(string name);
/** Holds if is declared with the `type` keyword, so only types are exported. */
predicate isTypeOnly() {
hasTypeKeyword(this)
}
predicate isTypeOnly() { hasTypeKeyword(this) }
override predicate isAmbient() {
Stmt.super.isAmbient() or
@ -614,15 +610,10 @@ abstract class ReExportDeclaration extends ExportDeclaration {
*
* Gets the module from which this declaration re-exports.
*/
deprecated
ES2015Module getImportedModule() {
result = getReExportedModule()
}
deprecated ES2015Module getImportedModule() { result = getReExportedModule() }
/** Gets the module from which this declaration re-exports, if it is an ES2015 module. */
ES2015Module getReExportedES2015Module() {
result = getReExportedModule()
}
ES2015Module getReExportedES2015Module() { result = getReExportedModule() }
/** Gets the module from which this declaration re-exports. */
Module getReExportedModule() {
@ -635,7 +626,8 @@ abstract class ReExportDeclaration extends ExportDeclaration {
* Gets a module in a `node_modules/@types/` folder that matches the imported module name.
*/
private Module resolveFromTypeRoot() {
result.getFile() = min(TypeRootFolder typeRoot |
result.getFile() =
min(TypeRootFolder typeRoot |
|
typeRoot.getModuleFile(getImportedPath().getStringValue())
order by

Просмотреть файл

@ -43,9 +43,8 @@ abstract class EmailSender extends DataFlow::SourceNode {
*/
private class NodemailerEmailSender extends EmailSender, DataFlow::MethodCallNode {
NodemailerEmailSender() {
this = DataFlow::moduleMember("nodemailer", "createTransport")
.getACall()
.getAMethodCall("sendMail")
this =
DataFlow::moduleMember("nodemailer", "createTransport").getACall().getAMethodCall("sendMail")
}
override DataFlow::Node getPlainTextBody() { result = getOptionArgument(0, "text") }

Просмотреть файл

@ -253,12 +253,15 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
DataFlow::Node getExceptionTarget() {
if exists(this.getEnclosingStmt().getEnclosingTryCatchStmt())
then
result = DataFlow::parameterNode(this
result =
DataFlow::parameterNode(this
.getEnclosingStmt()
.getEnclosingTryCatchStmt()
.getACatchClause()
.getAParameter())
else result = any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn()
else
result =
any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn()
}
}

Просмотреть файл

@ -183,11 +183,8 @@ class Folder extends Container, @folder {
* HTML files will not be found by this method.
*/
File getJavaScriptFile(string stem) {
result = min(int p, string ext |
p = getFileExtensionPriority(ext)
|
getFile(stem, ext) order by p
)
result =
min(int p, string ext | p = getFileExtensionPriority(ext) | getFile(stem, ext) order by p)
}
/** Gets a subfolder contained in this folder. */

Просмотреть файл

@ -206,7 +206,8 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
/** Gets the cyclomatic complexity of this function. */
int getCyclomaticComplexity() {
result = 2 +
result =
2 +
sum(Expr nd |
nd.getContainer() = this and nd.isBranch()
|
@ -420,9 +421,7 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
/**
* Gets the call signature of this function, as determined by the TypeScript compiler, if any.
*/
CallSignatureType getCallSignature() {
declared_function_signature(this, result)
}
CallSignatureType getCallSignature() { declared_function_signature(this, result) }
}
/**

Просмотреть файл

@ -35,8 +35,10 @@ class CodeGeneratorMarkerComment extends GeneratedCodeMarkerComment {
*/
private predicate codeGeneratorMarkerComment(Comment c, string tool) {
exists(string toolPattern |
toolPattern = "js_of_ocaml|CoffeeScript|LiveScript|dart2js|ANTLR|PEG\\.js|Opal|JSX|jison(?:-lex)?|(?:Microsoft \\(R\\) AutoRest Code Generator)|purs" and
tool = c
toolPattern =
"js_of_ocaml|CoffeeScript|LiveScript|dart2js|ANTLR|PEG\\.js|Opal|JSX|jison(?:-lex)?|(?:Microsoft \\(R\\) AutoRest Code Generator)|purs" and
tool =
c
.getText()
.regexpCapture("(?s)[\\s*]*(?:parser |Code )?[gG]eneratedy? (?:from .*)?by (" +
toolPattern + ")\\b.*", 1)

Просмотреть файл

@ -5,23 +5,18 @@
import javascript
private import semmle.javascript.dataflow.InferredTypes
deprecated
module GlobalAccessPath {
deprecated module GlobalAccessPath {
/**
* DEPRECATED. Instead use `AccessPath::getAReferenceTo` with the result and parameter reversed.
*/
pragma[inline]
string fromReference(DataFlow::Node node) {
node = AccessPath::getAReferenceTo(result)
}
string fromReference(DataFlow::Node node) { node = AccessPath::getAReferenceTo(result) }
/**
* DEPRECATED. Instead use `AccessPath::getAnAssignmentTo` with the result and parameter reversed.
*/
pragma[inline]
string fromRhs(DataFlow::Node node) {
node = AccessPath::getAnAssignmentTo(result)
}
string fromRhs(DataFlow::Node node) { node = AccessPath::getAnAssignmentTo(result) }
/**
* DEPRECATED. Use `AccessPath::getAReferenceOrAssignmentTo`.
@ -67,9 +62,7 @@ module AccessPath {
}
/** Holds if this represents the root of the global access path. */
predicate isGlobal() {
this = DataFlow::globalAccessPathRootPseudoNode()
}
predicate isGlobal() { this = DataFlow::globalAccessPathRootPseudoNode() }
}
/**
@ -212,7 +205,8 @@ module AccessPath {
* ```
*/
private predicate isSelfAssignment(DataFlow::Node rhs) {
fromRhs(rhs, DataFlow::globalAccessPathRootPseudoNode()) = fromReference(rhs, DataFlow::globalAccessPathRootPseudoNode())
fromRhs(rhs, DataFlow::globalAccessPathRootPseudoNode()) =
fromReference(rhs, DataFlow::globalAccessPathRootPseudoNode())
}
/**
@ -418,8 +412,8 @@ module AccessPath {
*/
pragma[inline]
DataFlow::SourceNode getAnAliasedSourceNode(DataFlow::Node node) {
exists(DataFlow::SourceNode root, string accessPath |
node = AccessPath::getAReferenceTo(root, accessPath) and
exists(DataFlow::SourceNode root, string accessPath |
node = AccessPath::getAReferenceTo(root, accessPath) and
result = AccessPath::getAReferenceTo(root, accessPath)
)
or

Просмотреть файл

@ -49,9 +49,8 @@ private class DefaultHtmlSanitizerCall extends HtmlSanitizerCall {
callee = LodashUnderscore::member("escape")
or
exists(string name | name = "encode" or name = "encodeNonUTF" |
callee = DataFlow::moduleMember("html-entities", _)
.getAnInstantiation()
.getAPropertyRead(name) or
callee =
DataFlow::moduleMember("html-entities", _).getAnInstantiation().getAPropertyRead(name) or
callee = DataFlow::moduleMember("html-entities", _).getAPropertyRead(name)
)
or

Просмотреть файл

@ -1,6 +1,7 @@
/**
* Contains classes for recognizing array and string inclusion tests.
*/
private import javascript
/**

Просмотреть файл

@ -142,5 +142,6 @@ class Locatable extends @locatable {
*/
private class FileLocatable extends File, Locatable {
override Location getLocation() { result = File.super.getLocation() }
override string toString() { result = File.super.toString() }
}

Просмотреть файл

@ -140,7 +140,8 @@ abstract class Import extends ASTNode {
* Gets a module in a `node_modules/@types/` folder that matches the imported module name.
*/
private Module resolveFromTypeRoot() {
result.getFile() = min(TypeRootFolder typeRoot |
result.getFile() =
min(TypeRootFolder typeRoot |
|
typeRoot.getModuleFile(getImportedPath().getValue())
order by

Просмотреть файл

@ -243,7 +243,8 @@ class Require extends CallExpr, Import {
private File load(int priority) {
exists(int r | getEnclosingModule().searchRoot(getImportedPath(), _, r) |
result = loadAsFile(this, r, priority - prioritiesPerCandidate() * r) or
result = loadAsDirectory(this, r,
result =
loadAsDirectory(this, r,
priority - (prioritiesPerCandidate() * r + numberOfExtensions() + 1))
)
}

Просмотреть файл

@ -92,7 +92,7 @@ File resolveMainModule(PackageJSON pkg, int priority) {
not exists(main.resolve()) and
not exists(main.getExtension()) and
exists(int n | n = main.getNumComponent() |
result = tryExtensions(main.resolveUpTo(n-1), main.getComponent(n-1), priority)
result = tryExtensions(main.resolveUpTo(n - 1), main.getComponent(n - 1), priority)
)
)
else result = tryExtensions(pkg.getFile().getParentContainer(), "index", priority)

Просмотреть файл

@ -128,17 +128,13 @@ private module PromiseFlow {
/**
* Gets the pseudo-field used to describe resolved values in a promise.
*/
string resolveField() {
result = "$PromiseResolveField$"
}
string resolveField() { result = "$PromiseResolveField$" }
/**
* Gets the pseudo-field used to describe rejected values in a promise.
*/
string rejectField() {
result = "$PromiseRejectField$"
}
string rejectField() { result = "$PromiseRejectField$" }
/**
* A flow step describing a promise definition.
*
@ -146,9 +142,8 @@ private module PromiseFlow {
*/
class PromiseDefitionStep extends DataFlow::AdditionalFlowStep {
PromiseDefinition promise;
PromiseDefitionStep() {
this = promise
}
PromiseDefitionStep() { this = promise }
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
prop = resolveField() and
@ -170,15 +165,14 @@ private module PromiseFlow {
succ = this
}
}
/**
* A flow step describing the a Promise.resolve (and similar) call.
*/
class CreationStep extends DataFlow::AdditionalFlowStep {
PromiseCreationCall promise;
CreationStep() {
this = promise
}
CreationStep() { this = promise }
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
prop = resolveField() and
@ -194,7 +188,6 @@ private module PromiseFlow {
}
}
/**
* A load step loading the pseudo-field describing that the promise is rejected.
* The rejected value is thrown as a exception.
@ -202,6 +195,7 @@ private module PromiseFlow {
class AwaitStep extends DataFlow::AdditionalFlowStep {
DataFlow::Node operand;
AwaitExpr await;
AwaitStep() {
this.getEnclosingExpr() = await and
operand.getEnclosingExpr() = await.getOperand()
@ -222,9 +216,7 @@ private module PromiseFlow {
* A flow step describing the data-flow related to the `.then` method of a promise.
*/
class ThenStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
ThenStep() {
this.getMethodName() = "then"
}
ThenStep() { this.getMethodName() = "then" }
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
prop = resolveField() and
@ -235,7 +227,7 @@ private module PromiseFlow {
pred = getReceiver() and
succ = getCallback(1).getParameter(0)
}
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
not exists(this.getArgument(1)) and
prop = rejectField() and
@ -244,17 +236,17 @@ private module PromiseFlow {
or
// read the value of a resolved/rejected promise that is returned
(prop = rejectField() or prop = resolveField()) and
pred = getCallback([0..1]).getAReturn() and
pred = getCallback([0 .. 1]).getAReturn() and
succ = this
}
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
prop = resolveField() and
pred = getCallback([0..1]).getAReturn() and
pred = getCallback([0 .. 1]).getAReturn() and
succ = this
or
prop = rejectField() and
pred = getCallback([0..1]).getExceptionalReturn() and
pred = getCallback([0 .. 1]).getExceptionalReturn() and
succ = this
}
}
@ -263,9 +255,7 @@ private module PromiseFlow {
* A flow step describing the data-flow related to the `.catch` method of a promise.
*/
class CatchStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
CatchStep() {
this.getMethodName() = "catch"
}
CatchStep() { this.getMethodName() = "catch" }
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
prop = rejectField() and
@ -299,9 +289,7 @@ private module PromiseFlow {
* A flow step describing the data-flow related to the `.finally` method of a promise.
*/
class FinallyStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
FinallyStep() {
this.getMethodName() = "finally"
}
FinallyStep() { this.getMethodName() = "finally" }
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
(prop = resolveField() or prop = rejectField()) and
@ -332,15 +320,13 @@ predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
// from `x` to `Promise.resolve(x)`
pred = succ.(PromiseCreationCall).getValue()
or
exists(DataFlow::MethodCallNode thn |
thn.getMethodName() = "then"
|
exists(DataFlow::MethodCallNode thn | thn.getMethodName() = "then" |
// from `p` to `x` in `p.then(x => ...)`
pred = thn.getReceiver() and
succ = thn.getCallback(0).getParameter(0)
or
// from `v` to `p.then(x => return v)`
pred = thn.getCallback([0..1]).getAReturn() and
pred = thn.getCallback([0 .. 1]).getAReturn() and
succ = thn
)
or
@ -406,22 +392,19 @@ module Bluebird {
override DataFlow::Node getValue() { result = getArgument(0) }
}
/**
* An aggregated promise produced either by `Promise.all`, `Promise.race` or `Promise.map`.
* An aggregated promise produced either by `Promise.all`, `Promise.race` or `Promise.map`.
*/
class AggregateBluebirdPromiseDefinition extends PromiseCreationCall {
AggregateBluebirdPromiseDefinition() {
exists(string m | m = "all" or m = "race" or m = "map" |
this = bluebird().getAMemberCall(m)
)
exists(string m | m = "all" or m = "race" or m = "map" | this = bluebird().getAMemberCall(m))
}
override DataFlow::Node getValue() {
result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement()
}
}
}
/**

Просмотреть файл

@ -296,9 +296,7 @@ class RegExpSequence extends RegExpTerm, @regexp_seq {
forall(RegExpTerm child | child = getAChild() | child.isNullable())
}
override string getConstantValue() {
result = getConstantValue(0)
}
override string getConstantValue() { result = getConstantValue(0) }
/**
* Gets the single string matched by the `i`th child and all following children of
@ -308,13 +306,11 @@ class RegExpSequence extends RegExpTerm, @regexp_seq {
i = getNumChild() and
result = ""
or
result = getChild(i).getConstantValue() + getConstantValue(i+1)
result = getChild(i).getConstantValue() + getConstantValue(i + 1)
}
/** Gets the element preceding `element` in this sequence. */
RegExpTerm previousElement(RegExpTerm element) {
element = nextElement(result)
}
/** Gets the element preceding `element` in this sequence. */
RegExpTerm previousElement(RegExpTerm element) { element = nextElement(result) }
/** Gets the element following `element` in this sequence. */
RegExpTerm nextElement(RegExpTerm element) {
@ -834,7 +830,7 @@ class RegExpParseError extends Error, @regexp_parse_error {
}
/**
* Holds if `func` is a method defined on `String.prototype` with name `name`.
* Holds if `func` is a method defined on `String.prototype` with name `name`.
*/
private predicate isNativeStringMethod(Function func, string name) {
exists(ExternalInstanceMemberDecl decl |
@ -856,9 +852,7 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
exists(DataFlow::MethodCallNode mce, string methodName |
mce.getReceiver().analyze().getAType() = TTString() and
mce.getMethodName() = methodName and
not exists(Function func |
func = mce.getACallee()
|
not exists(Function func | func = mce.getACallee() |
not isNativeStringMethod(func, methodName)
)
|

Просмотреть файл

@ -25,9 +25,8 @@ class FirstLineOf extends Locatable {
if xl = startline
then endcolumn = xc
else
endcolumn = max(int c |
any(Location l).hasLocationInfo(filepath, startline, _, startline, c)
)
endcolumn =
max(int c | any(Location l).hasLocationInfo(filepath, startline, _, startline, c))
)
}
}

Просмотреть файл

@ -647,9 +647,7 @@ class SsaPhiNode extends SsaPseudoDefinition, TPhi {
result = getDefReachingEndOf(bb, getSourceVariable())
}
override SsaVariable getAnInput() {
result = getInputFromBlock(_)
}
override SsaVariable getAnInput() { result = getInputFromBlock(_) }
override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
bb = getBasicBlock() and v = getSourceVariable() and i = -1
@ -676,9 +674,7 @@ class SsaPhiNode extends SsaPseudoDefinition, TPhi {
* gets that variable.
*/
SsaVariable getRephinedVariable() {
forex(SsaVariable input | input = getAnInput() |
result = getRefinedVariable(input)
)
forex(SsaVariable input | input = getAnInput() | result = getRefinedVariable(input))
}
}

Просмотреть файл

@ -49,7 +49,8 @@ class DirectEval extends CallExpr {
* Models `Array.prototype.map` and friends as partial invocations that pass their second
* argument as the receiver to the callback.
*/
private class ArrayIterationCallbackAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, DataFlow::MethodCallNode {
private class ArrayIterationCallbackAsPartialInvoke extends DataFlow::PartialInvokeNode::Range,
DataFlow::MethodCallNode {
ArrayIterationCallbackAsPartialInvoke() {
getNumArgument() = 2 and
// Filter out library methods named 'forEach' etc

Просмотреть файл

@ -55,15 +55,15 @@ class Stmt extends @stmt, ExprOrStmt, Documentable {
}
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
/**
* Gets the `try` statement with a catch block containing this statement without
* crossing function boundaries or other `try ` statements with catch blocks.
*/
* Gets the `try` statement with a catch block containing this statement without
* crossing function boundaries or other `try ` statements with catch blocks.
*/
TryStmt getEnclosingTryCatchStmt() {
getParentStmt+() = result.getBody() and
exists(result.getACatchClause()) and
not exists(TryStmt mid | exists(mid.getACatchClause()) |
not exists(TryStmt mid | exists(mid.getACatchClause()) |
getParentStmt+() = mid.getBody() and mid.getParentStmt+() = result.getBody()
)
}

Просмотреть файл

@ -165,10 +165,16 @@ module StringOps {
StartsWith_Substring() {
astNode.hasOperands(call.asExpr(), substring.asExpr()) and
(call.getMethodName() = "substring" or call.getMethodName() = "substr" or call.getMethodName() = "slice") and
(
call.getMethodName() = "substring" or
call.getMethodName() = "substr" or
call.getMethodName() = "slice"
) and
call.getNumArgument() = 2 and
(
AccessPath::getAnAliasedSourceNode(substring).getAPropertyRead("length").flowsTo(call.getArgument(1))
AccessPath::getAnAliasedSourceNode(substring)
.getAPropertyRead("length")
.flowsTo(call.getArgument(1))
or
substring.getStringValue().length() = call.getArgument(1).asExpr().getIntValue()
)
@ -502,7 +508,8 @@ module StringOps {
result = getStringValue()
or
not exists(getStringValue()) and
result = strictconcat(StringLiteralLike leaf |
result =
strictconcat(StringLiteralLike leaf |
leaf = getALeaf().asExpr()
|
leaf.getStringValue() order by leaf.getFirstToken().getIndex()

Просмотреть файл

@ -939,9 +939,7 @@ class PredicateTypeExpr extends @predicatetypeexpr, TypeExpr {
/**
* Holds if this is a type of form `asserts E is T` or `asserts E`.
*/
predicate hasAssertsKeyword() {
hasAssertsKeyword(this)
}
predicate hasAssertsKeyword() { hasAssertsKeyword(this) }
}
/**
@ -954,9 +952,7 @@ class PredicateTypeExpr extends @predicatetypeexpr, TypeExpr {
* ```
*/
class IsTypeExpr extends PredicateTypeExpr {
IsTypeExpr() {
exists(getPredicateType())
}
IsTypeExpr() { exists(getPredicateType()) }
}
/**
@ -2312,18 +2308,14 @@ class EnumLiteralType extends TypeReference {
* A type that refers to a type alias.
*/
class TypeAliasReference extends TypeReference {
TypeAliasReference() {
type_alias(this, _)
}
TypeAliasReference() { type_alias(this, _) }
/**
* Gets the type behind the type alias.
*
* For example, for `type B<T> = T[][]`, this maps the type `B<number>` to `number[][]`.
*/
Type getAliasedType() {
type_alias(this, result)
}
Type getAliasedType() { type_alias(this, result) }
}
/**
@ -2635,9 +2627,7 @@ class CallSignatureType extends @signature_type {
*
* For example, for the signature `(...y: string[])`, this gets the type `string[]`.
*/
PlainArrayType getRestParameterArrayType() {
signature_rest_parameter(this, result)
}
PlainArrayType getRestParameterArrayType() { signature_rest_parameter(this, result) }
}
/**

Просмотреть файл

@ -189,10 +189,8 @@ class Variable extends @variable, LexicalName {
*/
predicate isCaptured() {
this instanceof GlobalVariable or
getAnAccess().getContainer().getFunctionBoundary() != this
.(LocalVariable)
.getDeclaringContainer()
.getFunctionBoundary()
getAnAccess().getContainer().getFunctionBoundary() !=
this.(LocalVariable).getDeclaringContainer().getFunctionBoundary()
}
/** Holds if there is a declaration of this variable in `tl`. */
@ -764,9 +762,7 @@ class Parameter extends BindingPattern {
* function f(x?: number) {}
* ```
*/
predicate isDeclaredOptional() {
isOptionalParameterDeclaration(this)
}
predicate isDeclaredOptional() { isOptionalParameterDeclaration(this) }
}
/**

Просмотреть файл

@ -18,9 +18,7 @@ import javascript
private class BackwardExploringConfiguration extends DataFlow::Configuration {
DataFlow::Configuration cfg;
BackwardExploringConfiguration() {
this = cfg
}
BackwardExploringConfiguration() { this = cfg }
override predicate isSource(DataFlow::Node node) { any() }

Просмотреть файл

@ -1035,7 +1035,9 @@ private predicate flowIntoHigherOrderCall(
summary = oldSummary.append(PathSummary::call())
)
or
exists(DataFlow::SourceNode cb, DataFlow::FunctionNode f, int i, int boundArgs, PathSummary oldSummary |
exists(
DataFlow::SourceNode cb, DataFlow::FunctionNode f, int i, int boundArgs, PathSummary oldSummary
|
higherOrderCall(pred, cb, i, cfg, oldSummary) and
cb = CallGraph::getABoundFunctionReference(f, boundArgs, false) and
succ = f.getParameter(boundArgs + i) and
@ -1494,9 +1496,9 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat
}
/**
* A guard node for a variable in a negative condition, such as `x` in `if(!x)`.
* Can be added to a `isBarrier` in a data-flow configuration to block flow through such checks.
*/
* A guard node for a variable in a negative condition, such as `x` in `if(!x)`.
* Can be added to a `isBarrier` in a data-flow configuration to block flow through such checks.
*/
class VarAccessBarrier extends DataFlow::Node {
VarAccessBarrier() {
exists(ConditionGuardNode guard, SsaRefinementNode refinement |

Просмотреть файл

@ -87,10 +87,10 @@ module DataFlow {
Expr asExpr() { this = TValueNode(result) }
/**
* Gets the expression enclosing this data flow node.
* In most cases the result is the same as `asExpr()`, however this method
* additionally the `InvokeExpr` corresponding to reflective calls, and the `Parameter`
* for a `DataFlow::ParameterNode`.
* Gets the expression enclosing this data flow node.
* In most cases the result is the same as `asExpr()`, however this method
* additionally the `InvokeExpr` corresponding to reflective calls, and the `Parameter`
* for a `DataFlow::ParameterNode`.
*/
Expr getEnclosingExpr() {
result = asExpr() or
@ -536,10 +536,10 @@ module DataFlow {
*/
pragma[noinline]
predicate accesses(Node base, string p) { getBase() = base and getPropertyName() = p }
/**
* Holds if this data flow node reads or writes a private field in a class.
*/
*/
predicate isPrivateField() {
getPropertyName().charAt(0) = "#" and getPropertyNameExpr() instanceof Label
}
@ -860,7 +860,7 @@ module DataFlow {
override Expr getPropertyNameExpr() { none() }
override string getPropertyName() {
exists (int i |
exists(int i |
elt = pattern.getElement(i) and
result = i.toString()
)
@ -872,7 +872,6 @@ module DataFlow {
*/
private class ImportSpecifierAsPropRead extends PropRead, ValueNode {
override ImportSpecifier astNode;
ImportDeclaration imprt;
ImportSpecifierAsPropRead() {
@ -894,9 +893,7 @@ module DataFlow {
private class ForOfLvalueAsPropRead extends PropRead {
ForOfStmt stmt;
ForOfLvalueAsPropRead() {
this = lvalueNode(stmt.getLValue())
}
ForOfLvalueAsPropRead() { this = lvalueNode(stmt.getLValue()) }
override Node getBase() { result = stmt.getIterationDomain().flow() }
@ -1010,7 +1007,7 @@ module DataFlow {
* Gets a pseudo-node representing the root of a global access path.
*/
DataFlow::Node globalAccessPathRootPseudoNode() { result instanceof TGlobalAccessPathRoot }
/**
* Gets a data flow node representing the underlying call performed by the given
* call to `Function.prototype.call` or `Function.prototype.apply`.

Просмотреть файл

@ -16,9 +16,7 @@ import javascript
private class ForwardExploringConfiguration extends DataFlow::Configuration {
DataFlow::Configuration cfg;
ForwardExploringConfiguration() {
this = cfg
}
ForwardExploringConfiguration() { this = cfg }
override predicate isSink(DataFlow::Node node) { any() }

Просмотреть файл

@ -134,6 +134,7 @@ class NonPrimitiveType extends InferredType {
* Gets a pretty-printed list of all type tags in alphabetical order.
*/
string ppAllTypeTags() {
result = "boolean, class, date, function, null, number, object, regular expression," +
result =
"boolean, class, date, function, null, number, object, regular expression," +
"string or undefined"
}

Просмотреть файл

@ -9,7 +9,7 @@ private import semmle.javascript.dependencies.Dependencies
private import internal.CallGraphs
/**
* A data flow node corresponding to an expression.
* A data flow node corresponding to an expression.
*
* Examples:
* ```js
@ -147,7 +147,8 @@ class InvokeNode extends DataFlow::SourceNode {
*/
ParameterNode getABoundCallbackParameter(int callback, int param) {
exists(int boundArgs |
result = getArgument(callback).getABoundFunctionValue(boundArgs).getParameter(param + boundArgs)
result =
getArgument(callback).getABoundFunctionValue(boundArgs).getParameter(param + boundArgs)
)
}
@ -548,9 +549,7 @@ class RegExpLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode {
RegExpTerm getRoot() { result = astNode.getRoot() }
/** Gets the flags of this regular expression literal. */
string getFlags() {
result = astNode.getFlags()
}
string getFlags() { result = astNode.getFlags() }
}
/**
@ -581,10 +580,9 @@ class ArrayConstructorInvokeNode extends DataFlow::InvokeNode {
/** Gets the initial size of the created array, if it can be determined. */
int getSize() {
if getNumArgument() = 1 then
result = getArgument(0).getIntValue()
else
result = count(getAnElement())
if getNumArgument() = 1
then result = getArgument(0).getIntValue()
else result = count(getAnElement())
}
}
@ -596,7 +594,7 @@ class ArrayConstructorInvokeNode extends DataFlow::InvokeNode {
* Examples:
* ```js
* ['apple', 'orange'];
* Array('apple', 'orange')
* Array('apple', 'orange')
* new Array('apple', 'orange')
* Array(16)
* new Array(16)
@ -1236,7 +1234,9 @@ class PartialInvokeNode extends DataFlow::Node {
/**
* Gets the node holding the receiver to be passed to the bound function, if specified.
*/
DataFlow::Node getBoundReceiver(DataFlow::Node callback) { result = range.getBoundReceiver(callback) }
DataFlow::Node getBoundReceiver(DataFlow::Node callback) {
result = range.getBoundReceiver(callback)
}
}
module PartialInvokeNode {
@ -1247,7 +1247,9 @@ module PartialInvokeNode {
/**
* Holds if `argument` is passed as argument `index` to the function in `callback`.
*/
predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) { none() }
predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) {
none()
}
/**
* Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound.
@ -1259,8 +1261,7 @@ module PartialInvokeNode {
*
* Gets the node holding the receiver to be passed to the bound function, if specified.
*/
deprecated
DataFlow::Node getBoundReceiver() { none() }
deprecated DataFlow::Node getBoundReceiver() { none() }
/**
* Gets the node holding the receiver to be passed to `callback`.
@ -1269,12 +1270,11 @@ module PartialInvokeNode {
}
/**
* A partial call through the built-in `Function.prototype.bind`.
*/
* A partial call through the built-in `Function.prototype.bind`.
*/
private class BindPartialCall extends PartialInvokeNode::Range, DataFlow::MethodCallNode {
BindPartialCall() {
getMethodName() = "bind" and
// Avoid overlap with angular.bind and goog.bind
not this = AngularJS::angular().getAMethodCall() and
not getReceiver().accessesGlobal("goog")
@ -1299,8 +1299,8 @@ module PartialInvokeNode {
}
/**
* A partial call through `_.partial`.
*/
* A partial call through `_.partial`.
*/
private class LodashPartialCall extends PartialInvokeNode::Range, DataFlow::CallNode {
LodashPartialCall() { this = LodashUnderscore::member("partial").getACall() }
@ -1323,9 +1323,7 @@ module PartialInvokeNode {
private class RamdaPartialCall extends PartialInvokeNode::Range, DataFlow::CallNode {
RamdaPartialCall() { this = DataFlow::moduleMember("ramda", "partial").getACall() }
private DataFlow::ArrayCreationNode getArgumentsArray() {
result.flowsTo(getArgument(1))
}
private DataFlow::ArrayCreationNode getArgumentsArray() { result.flowsTo(getArgument(1)) }
override predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) {
callback = getArgument(0) and
@ -1376,17 +1374,13 @@ deprecated class AdditionalPartialInvokeNode = PartialInvokeNode::Range;
* ```
*/
class RegExpConstructorInvokeNode extends DataFlow::InvokeNode {
RegExpConstructorInvokeNode() {
this = DataFlow::globalVarRef("RegExp").getAnInvocation()
}
RegExpConstructorInvokeNode() { this = DataFlow::globalVarRef("RegExp").getAnInvocation() }
/**
* Gets the AST of the regular expression created here, provided that the
* first argument is a string literal.
*/
RegExpTerm getRoot() {
result = getArgument(0).asExpr().(StringLiteral).asRegExp()
}
RegExpTerm getRoot() { result = getArgument(0).asExpr().(StringLiteral).asRegExp() }
/**
* Gets the flags provided in the second argument, or an empty string if no
@ -1462,13 +1456,9 @@ class RegExpCreationNode extends DataFlow::SourceNode {
t.start() and
result = this
or
exists(DataFlow::TypeTracker t2 |
result = getAReference(t2).track(t2, t)
)
exists(DataFlow::TypeTracker t2 | result = getAReference(t2).track(t2, t))
}
/** Gets a data flow node referring to this regular expression. */
DataFlow::SourceNode getAReference() {
result = getAReference(DataFlow::TypeTracker::end())
}
DataFlow::SourceNode getAReference() { result = getAReference(DataFlow::TypeTracker::end()) }
}

Просмотреть файл

@ -341,7 +341,7 @@ module TaintTracking {
pred = call.getAnArgument() and
succ = call
or
// `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
// `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
call.(DataFlow::MethodCallNode).calls(pred, "concat") and
succ = call
or
@ -574,7 +574,6 @@ module TaintTracking {
succ = this
}
}
/**
* A taint propagating data flow edge arising from calling `String.prototype.match()`.
@ -583,7 +582,7 @@ module TaintTracking {
StringMatchTaintStep() {
this.getMethodName() = "match" and
this.getNumArgument() = 1 and
this.getArgument(0) .analyze().getAType() = TTRegExp()
this.getArgument(0).analyze().getAType() = TTRegExp()
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
@ -696,9 +695,7 @@ module TaintTracking {
* A taint step through the Node.JS function `util.inspect(..)`.
*/
class UtilInspectTaintStep extends AdditionalTaintStep, DataFlow::InvokeNode {
UtilInspectTaintStep() {
this = DataFlow::moduleImport("util").getAMemberCall("inspect")
}
UtilInspectTaintStep() { this = DataFlow::moduleImport("util").getAMemberCall("inspect") }
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
succ = this and
@ -719,14 +716,16 @@ module TaintTracking {
mce = astNode and mce.calls(base, m) and firstArg = mce.getArgument(0)
|
// /re/.test(u) or /re/.exec(u)
RegExp::isGenericRegExpSanitizer(RegExp::getRegExpObjectFromNode(base.flow()), sanitizedOutcome) and
RegExp::isGenericRegExpSanitizer(RegExp::getRegExpObjectFromNode(base.flow()),
sanitizedOutcome) and
(m = "test" or m = "exec") and
firstArg = expr
or
// u.match(/re/) or u.match("re")
base = expr and
m = "match" and
RegExp::isGenericRegExpSanitizer(RegExp::getRegExpFromNode(firstArg.flow()), sanitizedOutcome)
RegExp::isGenericRegExpSanitizer(RegExp::getRegExpFromNode(firstArg.flow()),
sanitizedOutcome)
)
or
// m = /re/.exec(u) and similar

Просмотреть файл

@ -137,10 +137,11 @@ module StepSummary {
summary = LoadStep(prop)
)
) and
if param = fun.getAParameter() then (
if param = fun.getAParameter()
then
// Step from argument to call site.
argumentPassing(succ, pred, fun.getFunction(), param)
) else (
else (
// Step from captured parameter to local call sites
pred = param and
succ = fun.getAnInvocation()

Просмотреть файл

@ -128,8 +128,9 @@ class AccessPath extends TAccessPath {
exists(AccessPath base, PropertyName name, string rest |
rest = "." + any(string s | name = StaticPropertyName(s))
or
rest = "[" +
any(SsaVariable var | name = DynamicPropertyName(var)).getSourceVariable().getName() + "]"
rest =
"[" + any(SsaVariable var | name = DynamicPropertyName(var)).getSourceVariable().getName() +
"]"
|
result = base.toString() + rest and
this = MkAccessStep(base, name)

Просмотреть файл

@ -1,6 +1,7 @@
/**
* Internal predicates for computing the call graph.
*/
private import javascript
cached
@ -24,21 +25,22 @@ module CallGraph {
* from underlying class tracking if the function came from a class or instance.
*/
pragma[nomagic]
private
DataFlow::SourceNode getAFunctionReference(DataFlow::FunctionNode function, int imprecision, DataFlow::TypeTracker t) {
private DataFlow::SourceNode getAFunctionReference(
DataFlow::FunctionNode function, int imprecision, DataFlow::TypeTracker t
) {
t.start() and
exists(Function fun |
fun = function.getFunction() and
fun = getAFunctionValue(result)
|
if isIndefiniteGlobal(result) then
if isIndefiniteGlobal(result)
then
fun.getFile() = result.getFile() and imprecision = 0
or
fun.inExternsFile() and imprecision = 1
or
imprecision = 2
else
imprecision = 0
else imprecision = 0
)
or
imprecision = 0 and
@ -73,8 +75,9 @@ module CallGraph {
* with `function` as the underlying function.
*/
pragma[nomagic]
private
DataFlow::SourceNode getABoundFunctionReferenceAux(DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t) {
private DataFlow::SourceNode getABoundFunctionReferenceAux(
DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t
) {
exists(DataFlow::PartialInvokeNode partial, DataFlow::Node callback |
result = partial.getBoundFunction(callback, boundArgs) and
getAFunctionReference(function, 0, t.continue()).flowsTo(callback)
@ -87,8 +90,10 @@ module CallGraph {
}
pragma[noinline]
private
DataFlow::SourceNode getABoundFunctionReferenceAux(DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t, DataFlow::StepSummary summary) {
private DataFlow::SourceNode getABoundFunctionReferenceAux(
DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t,
DataFlow::StepSummary summary
) {
exists(DataFlow::SourceNode prev |
prev = getABoundFunctionReferenceAux(function, boundArgs, t) and
DataFlow::StepSummary::step(prev, result, summary)
@ -100,7 +105,9 @@ module CallGraph {
* with `function` as the underlying function.
*/
cached
DataFlow::SourceNode getABoundFunctionReference(DataFlow::FunctionNode function, int boundArgs, boolean contextDependent) {
DataFlow::SourceNode getABoundFunctionReference(
DataFlow::FunctionNode function, int boundArgs, boolean contextDependent
) {
exists(DataFlow::TypeTracker t |
result = getABoundFunctionReferenceAux(function, boundArgs, t) and
t.end() and
@ -116,8 +123,9 @@ module CallGraph {
* This predicate may be overridden to customize the class hierarchy analysis.
*/
pragma[nomagic]
private
DataFlow::PropRead getAnInstanceMemberAccess(DataFlow::ClassNode cls, string name, DataFlow::TypeTracker t) {
private DataFlow::PropRead getAnInstanceMemberAccess(
DataFlow::ClassNode cls, string name, DataFlow::TypeTracker t
) {
result = cls.getAnInstanceReference(t.continue()).getAPropertyRead(name)
or
exists(DataFlow::ClassNode subclass |

Просмотреть файл

@ -440,8 +440,8 @@ class PathSummary extends TPathSummary {
exists(Boolean hasReturn2, Boolean hasCall2, FlowLabel end2 |
that = MkPathSummary(hasReturn2, hasCall2, end, end2)
|
result = MkPathSummary(hasReturn.booleanOr(hasReturn2), hasCall.booleanOr(hasCall2), start,
end2) and
result =
MkPathSummary(hasReturn.booleanOr(hasReturn2), hasCall.booleanOr(hasCall2), start, end2) and
// avoid constructing invalid paths
not (hasCall = true and hasReturn2 = true)
)
@ -456,8 +456,8 @@ class PathSummary extends TPathSummary {
exists(Boolean hasReturn2, Boolean hasCall2 |
that = MkPathSummary(hasReturn2, hasCall2, FlowLabel::data(), FlowLabel::data())
|
result = MkPathSummary(hasReturn.booleanOr(hasReturn2), hasCall.booleanOr(hasCall2), start,
end) and
result =
MkPathSummary(hasReturn.booleanOr(hasReturn2), hasCall.booleanOr(hasCall2), start, end) and
// avoid constructing invalid paths
not (hasCall = true and hasReturn2 = true)
)
@ -474,8 +474,9 @@ class PathSummary extends TPathSummary {
(if hasReturn = true then withReturn = "with" else withReturn = "without") and
(if hasCall = true then withCall = "with" else withCall = "without")
|
result = "path " + withReturn + " return steps and " + withCall + " call steps " +
"transforming " + start + " into " + end
result =
"path " + withReturn + " return steps and " + withCall + " call steps " + "transforming " +
start + " into " + end
)
}
}

Просмотреть файл

@ -145,8 +145,9 @@ abstract class FrameworkLibraryWithGenericURL extends FrameworkLibraryWithURLReg
override string getAURLRegex() {
exists(string id | id = getId() or id = getAnAlias() |
result = ".*(?:^|/)" + id + "-(" + semverRegex() + ")" + variantRegex() + "\\.js" or
result = ".*/(?:\\w+@)?(" + semverRegex() + ")/(?:(?:dist|js|" + id + ")/)?" + id +
variantRegex() + "\\.js"
result =
".*/(?:\\w+@)?(" + semverRegex() + ")/(?:(?:dist|js|" + id + ")/)?" + id + variantRegex() +
"\\.js"
)
}
}
@ -158,7 +159,8 @@ abstract class FrameworkLibraryWithGenericURL extends FrameworkLibraryWithURLReg
* We ignore these when identifying frameworks.
*/
private string variantRegex() {
result = "([.-](slim|min|debug|dbg|umd|dev|all|testing|polyfills|" +
result =
"([.-](slim|min|debug|dbg|umd|dev|all|testing|polyfills|" +
"core|compat|more|modern|sandbox|rtl|with-addons|legacy))*"
}
@ -235,8 +237,8 @@ private predicate jQueryMarkerComment(Comment c, TopLevel tl, string version) {
tl = c.getTopLevel() and
exists(string txt | txt = c.getText() |
// more recent versions use this format
version = txt
.regexpCapture("(?s).*jQuery (?:JavaScript Library )?v(" + versionRegex() + ").*", 1)
version =
txt.regexpCapture("(?s).*jQuery (?:JavaScript Library )?v(" + versionRegex() + ").*", 1)
or
// earlier versions used this format
version = txt.regexpCapture("(?s).*jQuery (" + versionRegex() + ") - New Wave Javascript.*", 1)
@ -502,7 +504,8 @@ private class Lodash extends FrameworkLibraryWithGenericURL, FrameworkLibraryWit
Lodash() { this = "lodash" }
override string getAMarkerCommentRegex() {
result = "(?s).* (?:lod|Lo-D)ash (<VERSION>)" + "(?: \\(Custom Build\\))? " +
result =
"(?s).* (?:lod|Lo-D)ash (<VERSION>)" + "(?: \\(Custom Build\\))? " +
"<https?://lodash.com/>.*"
}
@ -842,7 +845,8 @@ private class ApplicationInsightsInstance extends FrameworkLibraryInstance {
string version;
ApplicationInsightsInstance() {
version = this
version =
this
.(TopLevel)
.getFile()
.getAbsolutePath()

Просмотреть файл

@ -832,7 +832,8 @@ private newtype TAngularScope =
} or
MkIsolateScope(CustomDirective dir) { dir.hasIsolateScope() } or
MkElementScope(DOM::ElementDefinition elem) {
any(DirectiveInstance d | not d.(CustomDirective).hasIsolateScope()).getAMatchingElement() = elem
any(DirectiveInstance d | not d.(CustomDirective).hasIsolateScope()).getAMatchingElement() =
elem
}
/**

Просмотреть файл

@ -152,7 +152,8 @@ private class TemplateFieldNgSourceProvider extends NgSourceProvider {
TemplateFieldNgSourceProvider() {
this = directive.getMember("template").asExpr() and
source = this
source =
this
.(ConstantString)
.getStringValue()
.regexpFind(getInterpolatedExpressionPattern(), _, offset)
@ -211,11 +212,8 @@ abstract class NgToken extends TNgToken {
*/
private int getIndex() {
exists(NgSource src, int start | this.at(src, start) |
start = rank[result + 1](NgToken someToken, int someStart |
someToken.at(src, someStart)
|
someStart
)
start =
rank[result + 1](NgToken someToken, int someStart | someToken.at(src, someStart) | someStart)
)
}
@ -278,7 +276,8 @@ private module Lexer {
NgOpTokenType() { this = "NgOpTokenType" }
override string getPattern() {
result = concat(string op |
result =
concat(string op |
op = "===" or
op = "!==" or
op = "==" or
@ -383,7 +382,8 @@ abstract class NgAstNode extends TNode {
*/
language[monotonicAggregates]
string ppChildren() {
result = concat(NgAstNode child, int idx |
result =
concat(NgAstNode child, int idx |
child = getChild(idx) and
not child instanceof Empty
|

Просмотреть файл

@ -553,10 +553,10 @@ module ClientRequest {
/**
* Gets a reference to an instance of `chrome-remote-interface`.
*
* An instantiation of `chrome-remote-interface` either accepts a callback or returns a promise.
*
* The `isPromise` parameter reflects whether the reference is a promise containing
* an instance of `chrome-remote-interface`, or an instance of `chrome-remote-interface`.
* An instantiation of `chrome-remote-interface` either accepts a callback or returns a promise.
*
* The `isPromise` parameter reflects whether the reference is a promise containing
* an instance of `chrome-remote-interface`, or an instance of `chrome-remote-interface`.
*/
private DataFlow::SourceNode chromeRemoteInterface(DataFlow::TypeTracker t, boolean isPromise) {
t.start() and

Просмотреть файл

@ -609,7 +609,8 @@ private module Forge {
NonKeyCipher() {
exists(string algorithmName | algorithm.matchesName(algorithmName) |
// require("forge").md.md5.create().update('The quick brown fox jumps over the lazy dog');
this = getAnImportNode()
this =
getAnImportNode()
.getAPropertyRead("md")
.getAPropertyRead(algorithmName)
.getAMemberCall("create")

Просмотреть файл

@ -138,9 +138,7 @@ module Electron {
result = this.getABoundCallbackParameter(1, 0).getAPropertyWrite("returnValue").getRhs()
}
override IPCDispatch getAReturnDispatch() {
result.getCalleeName() = "sendSync"
}
override IPCDispatch getAReturnDispatch() { result.getCalleeName() = "sendSync" }
}
/**
@ -168,7 +166,7 @@ module Electron {
}
/**
* Gets a registration that this dispatch can send an event to.
* Gets a registration that this dispatch can send an event to.
*/
override IPCSendRegistration getAReceiver() {
this.getEmitter() instanceof RendererProcess and

Просмотреть файл

@ -129,9 +129,7 @@ module EventRegistration {
* argument is the event handler callback.
*/
abstract class DefaultEventRegistration extends Range, DataFlow::InvokeNode {
override string getChannel() {
this.getArgument(0).mayHaveStringValue(result)
}
override string getChannel() { this.getArgument(0).mayHaveStringValue(result) }
override DataFlow::Node getReceivedItem(int i) {
result = this.getABoundCallbackParameter(1, i)
@ -187,13 +185,9 @@ module EventDispatch {
* is the `i`th item sent to the event handler.
*/
abstract class DefaultEventDispatch extends Range, DataFlow::InvokeNode {
override string getChannel() {
this.getArgument(0).mayHaveStringValue(result)
}
override string getChannel() { this.getArgument(0).mayHaveStringValue(result) }
override DataFlow::Node getSentItem(int i) {
result = this.getArgument(i + 1)
}
override DataFlow::Node getSentItem(int i) { result = this.getArgument(i + 1) }
override EventRegistration::Range getAReceiver() { this.getEmitter() = result.getEmitter() }
}
@ -223,4 +217,3 @@ private class EventEmitterTaintStep extends DataFlow::AdditionalFlowStep {
succ = dispatch
}
}

Просмотреть файл

@ -147,36 +147,34 @@ module Express {
this.getRequestMethod() = that.getRequestMethod()
}
}
/**
* A call that sets up a Passport router that includes the request object.
*/
private class PassportRouteSetup extends HTTP::Servers::StandardRouteSetup, CallExpr {
DataFlow::ModuleImportNode importNode;
DataFlow::FunctionNode callback;
// looks for this pattern: passport.use(new Strategy({passReqToCallback: true}, callback))
PassportRouteSetup() {
importNode = DataFlow::moduleImport("passport") and
this = importNode.getAMemberCall("use").asExpr() and
exists(DataFlow::NewNode strategy |
strategy.flowsToExpr(this.getArgument(0)) and
strategy.getNumArgument() = 2 and
// new Strategy({passReqToCallback: true}, ...)
strategy.getOptionArgument(0, "passReqToCallback").mayHaveBooleanValue(true) and
callback.flowsTo(strategy.getArgument(1))
exists(DataFlow::NewNode strategy |
strategy.flowsToExpr(this.getArgument(0)) and
strategy.getNumArgument() = 2 and
// new Strategy({passReqToCallback: true}, ...)
strategy.getOptionArgument(0, "passReqToCallback").mayHaveBooleanValue(true) and
callback.flowsTo(strategy.getArgument(1))
)
}
override Expr getServer() { result = importNode.asExpr() }
override DataFlow::SourceNode getARouteHandler() {
result = callback
}
override DataFlow::SourceNode getARouteHandler() { result = callback }
}
/**
* The callback given to passport in PassportRouteSetup.
* The callback given to passport in PassportRouteSetup.
*/
private class PassportRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler,
DataFlow::ValueNode {
@ -185,7 +183,7 @@ module Express {
PassportRouteHandler() { this = any(PassportRouteSetup setup).getARouteHandler() }
override SimpleParameter getRouteHandlerParameter(string kind) {
kind = "request" and
kind = "request" and
result = astNode.getParameter(0)
}
}

Просмотреть файл

@ -21,7 +21,8 @@ private class WalkFileNameSource extends FileNameSource {
WalkFileNameSource() {
// `stats.name` in `require('walk').walk(_).on(_, (_, stats) => stats.name)`
exists(DataFlow::FunctionNode callback |
callback = DataFlow::moduleMember("walk", "walk")
callback =
DataFlow::moduleMember("walk", "walk")
.getACall()
.getAMethodCall(EventEmitter::on())
.getCallback(1)
@ -66,7 +67,8 @@ private class GlobbyFileNameSource extends FileNameSource {
this = DataFlow::moduleMember(moduleName, "sync").getACall()
or
// `files` in `require('globby')(_).then(files => ...)`
this = DataFlow::moduleImport(moduleName)
this =
DataFlow::moduleImport(moduleName)
.getACall()
.getAMethodCall("then")
.getCallback(0)
@ -95,7 +97,8 @@ private class FastGlobFileNameSource extends FileNameSource {
)
or
// `file` in `require('fast-glob').stream(_).on(_, file => ...)`
this = DataFlow::moduleMember(moduleName, "stream")
this =
DataFlow::moduleMember(moduleName, "stream")
.getACall()
.getAMethodCall(EventEmitter::on())
.getCallback(1)

Просмотреть файл

@ -123,8 +123,7 @@ module HTTP {
*
* Gets the string `http` or `https`.
*/
deprecated
string httpOrHttps() { result = "http" or result = "https" }
deprecated string httpOrHttps() { result = "http" or result = "https" }
/**
* An expression whose value is sent as (part of) the body of an HTTP response.

Просмотреть файл

@ -6,7 +6,7 @@ import javascript
module Handlebars {
/**
* A reference to the Handlebars library.
* A reference to the Handlebars library.
*/
class Handlebars extends DataFlow::SourceNode {
Handlebars() {

Просмотреть файл

@ -11,7 +11,7 @@ module Koa {
*/
class AppDefinition extends HTTP::Servers::StandardServerDefinition, InvokeExpr {
AppDefinition() {
// `app = new Koa()` / `app = Koa()`
// `app = new Koa()` / `app = Koa()`
this = DataFlow::moduleImport("koa").getAnInvocation().asExpr()
}
}

Просмотреть файл

@ -58,9 +58,11 @@ private module Console {
}
override DataFlow::Node getAMessageComponent() {
if name = "assert"
then result = getArgument([1 .. getNumArgument()])
else result = getAnArgument()
(
if name = "assert"
then result = getArgument([1 .. getNumArgument()])
else result = getAnArgument()
)
or
result = getASpreadArgument()
}
@ -68,9 +70,7 @@ private module Console {
/**
* Gets the name of the console logging method, e.g. "log", "error", "assert", etc.
*/
string getName() {
result = name
}
string getName() { result = name }
}
}
@ -99,7 +99,8 @@ private module Winston {
*/
class WinstonLoggerCall extends LoggerCall, DataFlow::MethodCallNode {
WinstonLoggerCall() {
this = DataFlow::moduleMember("winston", "createLogger")
this =
DataFlow::moduleMember("winston", "createLogger")
.getACall()
.getAMethodCall(getAStandardLoggerMethodName())
}
@ -121,7 +122,8 @@ private module log4js {
*/
class Log4jsLoggerCall extends LoggerCall {
Log4jsLoggerCall() {
this = DataFlow::moduleMember("log4js", "getLogger")
this =
DataFlow::moduleMember("log4js", "getLogger")
.getACall()
.getAMethodCall(getAStandardLoggerMethodName())
}

Просмотреть файл

@ -84,9 +84,7 @@ private module MongoDB {
* of `mongodb.Collection`.
*/
private class CollectionFromType extends Collection {
CollectionFromType() {
hasUnderlyingType("mongodb", "Collection")
}
CollectionFromType() { hasUnderlyingType("mongodb", "Collection") }
}
/** Gets a data flow node referring to a MongoDB collection. */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше