mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
JS: introduce DefinedCustomAbstractValue
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user