Merge master into next.

This commit is contained in:
Aditya Sharad
2018-11-23 16:36:31 +00:00
394 changed files with 5820 additions and 1727 deletions

View File

@@ -4,7 +4,7 @@
* same id attribute, it may be interpreted differently
* by different browsers.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @id js/duplicate-html-id
* @tags maintainability
* correctness

View File

@@ -3,7 +3,7 @@
* @description If an HTML element has two attributes with the same name
* but different values, its behavior may be browser-dependent.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @id js/conflicting-html-attribute
* @tags maintainability
* correctness

View File

@@ -13,6 +13,7 @@
import javascript
import semmle.javascript.frameworks.Templating
import semmle.javascript.RestrictedLocations
/**
* Holds if the href attribute contains a host that we cannot determine statically.
@@ -53,4 +54,4 @@ where // `e` is a link that opens in a new browsing context (that is, it has `ta
not exists (DOM::AttributeDefinition attr | attr = e.getAnAttribute() |
not exists(attr.getName())
)
select e, "External links without noopener/noreferrer are a potential security risk."
select (FirstLineOf)e, "External links without noopener/noreferrer are a potential security risk."

View File

@@ -50,5 +50,14 @@ where maybeMissingThis(call, intendedTarget, gv)
decl.isNamespaceExport() and
call.getContainer().getEnclosingContainer*() instanceof NamespaceDeclaration
)
or
// call to global function with additional arguments
exists (Function self |
intendedTarget.getBody() = self and
call.getEnclosingFunction() = self and
call.flow().(DataFlow::CallNode).getNumArgument() > self.getNumParameter() and
not self.hasRestParameter() and
not self.usesArgumentsObject()
)
)
select call, "This call refers to a global function, and not the local method $@.", intendedTarget, intendedTarget.getName()

View File

@@ -3,7 +3,7 @@
* @description If a variable is not declared as a local variable, it becomes a global variable
* by default, which may be unintentional and could lead to unexpected behavior.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @id js/missing-variable-declaration
* @tags reliability
* maintainability

View File

@@ -10,15 +10,19 @@
*/
import javascript
/** Holds if `base` declares or inherits method `m` with the given `name`. */
predicate hasMethod(ClassDefinition base, string name, MethodDefinition m) {
m = base.getMethod(name) or
hasMethod(base.getSuperClassDefinition(), name, m)
}
/**
* Holds if `access` is in`fromMethod`, and it references `toMethod` through `this`.
*/
predicate isLocalMethodAccess(PropAccess access, MethodDefinition fromMethod, MethodDefinition toMethod) {
fromMethod.getDeclaringClass() = toMethod.getDeclaringClass() and
hasMethod(fromMethod.getDeclaringClass(), access.getPropertyName(), toMethod) and
access.getEnclosingFunction() = fromMethod.getBody() and
access.getBase() instanceof ThisExpr and
access.getPropertyName() = toMethod.getName()
access.getBase() instanceof ThisExpr
}
string getKind(MethodDefinition m) {

View File

@@ -3,7 +3,7 @@
* @description If two conditions in an 'if'-'else if' chain are identical, the
* second condition will never hold.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @id js/duplicate-condition
* @tags maintainability
* correctness

View File

@@ -3,7 +3,7 @@
* @description If two cases in a switch statement have the same label, the second case
* will never be executed.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @id js/duplicate-switch-case
* @tags maintainability
* correctness

View File

@@ -216,6 +216,13 @@ class ClassDefinition extends @classdefinition, ClassOrInterface, AST::ValueNode
)
}
/**
* Gets the definition of the super class of this class, if it can be determined.
*/
ClassDefinition getSuperClassDefinition() {
result = getSuperClass().analyze().getAValue().(AbstractClass).getClass()
}
}
/**

View File

@@ -224,6 +224,12 @@ class NgInjectDirective extends KnownDirective {
NgInjectDirective() { getDirectiveText().regexpMatch("ng(No)?Inject") }
}
/** A YUI compressor directive. */
class YuiDirective extends KnownDirective {
YuiDirective() {
getDirectiveText().regexpMatch("([a-z0-9_]+:nomunge, ?)*([a-z0-9_]+:nomunge)")
}
}
/** A SystemJS `deps` directive. */
class SystemJSDepsDirective extends KnownDirective {

View File

@@ -0,0 +1,158 @@
/**
* Provides classes for working with analysis-specific abstract values.
*
* Implement a subclass of `CustomAbstractValueDefinition` when the builtin
* abstract values of `AbstractValues.qll` are not expressive enough.
*
* For performance reasons, all subclasses of `CustomAbstractValueDefinition`
* should be part of the standard library.
*/
import javascript
private import internal.AbstractValuesImpl
private import InferredTypes
/**
* An abstract representation of an analysis-specific value.
*
* Wraps a `CustomAbstractValueDefinition`.
*/
class CustomAbstractValueFromDefinition extends AbstractValue, TCustomAbstractValueFromDefinition {
CustomAbstractValueDefinition def;
CustomAbstractValueFromDefinition() {
this = TCustomAbstractValueFromDefinition(def)
}
override InferredType getType() {
result = def.getType()
}
override boolean getBooleanValue() {
result = def.getBooleanValue()
}
override PrimitiveAbstractValue toPrimitive() {
result = def.toPrimitive()
}
override predicate isCoercibleToNumber() {
def.isCoercibleToNumber()
}
override predicate isIndefinite(DataFlow::Incompleteness cause) {
def.isIndefinite(cause)
}
override DefiniteAbstractValue getAPrototype() {
result = def.getAPrototype()
}
override predicate hasLocationInfo(string f, int startline, int startcolumn, int endline, int endcolumn) {
def.getLocation().hasLocationInfo(f, startline, startcolumn, endline, endcolumn)
}
override string toString() {
result = def.toString()
}
/**
* Gets the definition that induces this value.
*/
CustomAbstractValueDefinition getDefinition() {
result = def
}
/** Holds if this is a value whose properties the type inference tracks. */
predicate shouldTrackProperties() {
def.shouldTrackProperties()
}
}
/**
* A data-flow node that induces an analysis-specific abstract value.
*
* Enables modular extensions of `AbstractValue`.
*
* For performance reasons, all subclasses of this class should be part
* of the standard library.
*/
abstract class CustomAbstractValueDefinition extends Locatable {
/**
* Gets the type of some concrete value represented by the induced
* abstract value.
*/
abstract InferredType getType();
/**
* Gets the Boolean value that some concrete value represented by the
* induced abstract value coerces to.
*/
abstract boolean getBooleanValue();
/**
* Gets an abstract primitive value the induced abstract value coerces
* to.
*
* This abstractly models the `ToPrimitive` coercion described in the
* ECMAScript language specification.
*/
abstract PrimitiveAbstractValue toPrimitive();
/**
* Holds if the induced abstract value is coercible to a number, that
* is, it represents at least one concrete value for which the
* `ToNumber` conversion does not yield `NaN`.
*/
abstract predicate isCoercibleToNumber();
/**
* Holds if the induced abstract value is an indefinite value arising
* from the incompleteness `cause`.
*/
predicate isIndefinite(DataFlow::Incompleteness cause) {
none()
}
/**
* Gets an abstract value that represents a prototype object of the
* induced abstract value.
*/
AbstractValue getAPrototype() {
exists (AbstractProtoProperty proto |
proto.getBase() = getAbstractValue() and
result = proto.getAValue()
)
}
/**
* Gets the induced abstract value.
*/
AbstractValue getAbstractValue() {
result.(CustomAbstractValueFromDefinition).getDefinition() = this
}
/** Holds if this is a value whose properties the type inference tracks. */
abstract predicate shouldTrackProperties();
}
/**
* Flow analysis for custom abstract values.
*/
class CustomAbstractValueFromDefinitionNode extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
CustomAbstractValueFromDefinition val;
CustomAbstractValueFromDefinitionNode() {
val = TCustomAbstractValueFromDefinition(this.getAstNode())
}
override AbstractValue getALocalValue() {
result = val
}
}

View File

@@ -77,5 +77,6 @@ predicate shouldAlwaysTrackProperties(AbstractValue baseVal) {
predicate shouldTrackProperties(AbstractValue baseVal) {
shouldAlwaysTrackProperties(baseVal) or
baseVal instanceof AbstractObjectLiteral or
baseVal instanceof AbstractInstance
baseVal instanceof AbstractInstance or
baseVal.(CustomAbstractValueFromDefinition).shouldTrackProperties()
}

View File

@@ -6,6 +6,7 @@
import semmle.javascript.dataflow.AbstractValues
private import semmle.javascript.dataflow.InferredTypes
import semmle.javascript.dataflow.CustomAbstractValueDefinitions
/** An abstract value inferred by the flow analysis. */
cached newtype TAbstractValue =
@@ -101,6 +102,9 @@ cached newtype TAbstractValue =
or
/** A custom abstract value induced by `tag`. */
TCustomAbstractValue(CustomAbstractValueTag tag)
or
/** A custom abstract value induced by `def`. */
TCustomAbstractValueFromDefinition(CustomAbstractValueDefinition def)
/**
* Gets a definite abstract value with the given type.

View File

@@ -9,6 +9,11 @@ private string getDirectiveName(SlashStarComment c) {
result = c.getText().regexpCapture("(?s)\\s*(\\w+)\\b.*", 1)
}
/** Gets a function at the specified location. */
private Function getFunctionAt(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** A JSLint directive. */
abstract class JSLintDirective extends SlashStarComment {
/**
@@ -36,7 +41,7 @@ abstract class JSLintDirective extends SlashStarComment {
private Function getASurroundingFunction() {
exists (string path, int fsl, int fsc, int fel, int fec,
int dsl, int dsc, int del, int dec |
result.getLocation().hasLocationInfo(path, fsl, fsc, fel, fec) and
result = getFunctionAt(path, fsl, fsc, fel, fec) and
this.getLocation().hasLocationInfo(path, dsl, dsc, del, dec) |
// the function starts before this directive
(fsl < dsl or (fsl = dsl and fsc <= dsc))
@@ -96,6 +101,11 @@ abstract class JSLintGlobal extends Linting::GlobalDeclaration, JSLintDirective
override predicate appliesTo(ExprOrStmt s) {
JSLintDirective.super.appliesTo(s)
}
override predicate declaresGlobalForAccess(GlobalVarAccess gva) {
declaresGlobal(gva.getName(), _) and
getScope() = gva.getContainer().getEnclosingContainer*()
}
}
/** A JSLint `global` directive. */

View File

@@ -52,7 +52,7 @@ module CleartextLogging {
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) {
any (TaintTracking::StringConcatenationTaintStep s).step(src, trg)
StringConcatenation::taintStep(src, trg)
or
exists (string name | name = "toString" or name = "valueOf" |
src.(DataFlow::SourceNode).getAMethodCall(name) = trg