JS: introduce DefinedCustomAbstractValue

This commit is contained in:
Esben Sparre Andreasen
2018-08-08 08:26:37 +02:00
parent 2f0e693b38
commit 1d87c580b3
7 changed files with 286 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
/**
* 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 DefinedCustomAbstractValue extends AbstractValue, TDefinedCustomAbstractValue {
CustomAbstractValueDefinition def;
DefinedCustomAbstractValue() {
this = TDefinedCustomAbstractValue(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()
}
CustomAbstractValueDefinition getDefinition() {
result = def
}
predicate shouldTrackProperties() {
def.shouldTrackProperties()
}
}
/**
* A 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.(DefinedCustomAbstractValue).getDefinition() = this
}
abstract predicate shouldTrackProperties();
}
/**
* Flow analysis for custom abstract values.
*/
class DefinedCustomAbstractValueNode extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
DefinedCustomAbstractValue val;
DefinedCustomAbstractValueNode() {
val = TDefinedCustomAbstractValue(this.getAstNode())
}
override AbstractValue getALocalValue() {
result = val
}
}

View File

@@ -6,6 +6,7 @@
import semmle.javascript.dataflow.AbstractValues
private import semmle.javascript.dataflow.InferredTypes
import semmle.javascript.dataflow.DefinedCustomAbstractValues
/** 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`. */
TDefinedCustomAbstractValue(CustomAbstractValueDefinition def)
/**
* Gets a definite abstract value with the given type.