mirror of
https://github.com/github/codeql.git
synced 2026-01-22 02:44:45 +01:00
93 lines
3.1 KiB
Plaintext
93 lines
3.1 KiB
Plaintext
/**
|
|
* INTERNAL: Do not use directly; use `semmle.javascript.dataflow.TypeInference` instead.
|
|
*
|
|
* Provides the internal representation of abstract properties and related predicates.
|
|
*/
|
|
|
|
import javascript
|
|
private import AbstractValuesImpl
|
|
|
|
/**
|
|
* An abstract representation of a set of concrete properties, characterized
|
|
* by a base object (which is an abstract value for which properties are tracked)
|
|
* and a property name.
|
|
*/
|
|
newtype TAbstractProperty =
|
|
MkAbstractProperty(AbstractValue base, string prop) {
|
|
any(AnalyzedPropertyRead apr).reads(base, prop) and shouldTrackProperties(base)
|
|
or
|
|
any(AnalyzedPropertyWrite apw).writes(base, prop, _)
|
|
or
|
|
exists(getAnInitialPropertyValue(base, prop))
|
|
or
|
|
// make sure `__proto__` properties exist for all instance values
|
|
base instanceof AbstractInstance and
|
|
prop = "__proto__"
|
|
}
|
|
|
|
/**
|
|
* Holds if the result is known to be an initial value of property `propertyName` of one
|
|
* of the concrete objects represented by `baseVal`.
|
|
*/
|
|
AbstractValue getAnInitialPropertyValue(DefiniteAbstractValue baseVal, string propertyName) {
|
|
// initially, `module.exports === exports`
|
|
exists(Module m |
|
|
baseVal = TAbstractModuleObject(m) and
|
|
propertyName = "exports" and
|
|
result = TAbstractExportsObject(m)
|
|
)
|
|
or
|
|
// class members
|
|
result = getAnInitialMemberValue(getMember(baseVal, propertyName))
|
|
or
|
|
// object properties
|
|
exists(ValueProperty p |
|
|
baseVal.(AbstractObjectLiteral).getObjectExpr() = p.getObjectExpr() and
|
|
propertyName = p.getName() and
|
|
result = p.getInit().analyze().getALocalValue()
|
|
)
|
|
or
|
|
// `f.prototype` for functions `f`
|
|
propertyName = "prototype" and
|
|
result = TAbstractInstance(baseVal)
|
|
}
|
|
|
|
/**
|
|
* Gets a class member definition that we abstractly represent as a property of `baseVal`
|
|
* with the given `name`.
|
|
*/
|
|
private MemberDefinition getMember(DefiniteAbstractValue baseVal, string name) {
|
|
exists(ClassDefinition c | result = c.getMember(name) |
|
|
if result.isStatic() then baseVal = TAbstractClass(c) else baseVal = AbstractInstance::of(c)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets an abstract representation of the initial value of member definition `m`.
|
|
*
|
|
* For (non-accessor) methods, this is the abstract function corresponding to the
|
|
* method. For fields, it is an abstract representation of their initial value(s).
|
|
*/
|
|
private AbstractValue getAnInitialMemberValue(MemberDefinition m) {
|
|
not m instanceof AccessorMethodDefinition and
|
|
result = m.getInit().analyze().getALocalValue()
|
|
}
|
|
|
|
/**
|
|
* Holds if `baseVal` is an abstract value whose properties we track for the purposes
|
|
* of `getALocalValue`.
|
|
*/
|
|
predicate shouldAlwaysTrackProperties(AbstractValue baseVal) {
|
|
baseVal instanceof AbstractModuleObject or
|
|
baseVal instanceof AbstractExportsObject or
|
|
baseVal instanceof AbstractCallable
|
|
}
|
|
|
|
/** Holds if `baseVal` is an abstract value whose properties we track. */
|
|
predicate shouldTrackProperties(AbstractValue baseVal) {
|
|
shouldAlwaysTrackProperties(baseVal) or
|
|
baseVal instanceof AbstractObjectLiteral or
|
|
baseVal instanceof AbstractInstance or
|
|
baseVal.(CustomAbstractValueFromDefinition).shouldTrackProperties()
|
|
}
|