mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge pull request #1517 from asger-semmle/instance-type-tracking-final
Approved by xiemaisi
This commit is contained in:
@@ -67,14 +67,31 @@ class LocalObject extends DataFlow::SourceNode {
|
||||
not exposedAsReceiver(this)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasOwnProperty(string name) {
|
||||
// the property is defined in the initializer,
|
||||
any(DataFlow::PropWrite write).writes(this, name, _) and
|
||||
// and it is never deleted
|
||||
not exists(DeleteExpr del, DataFlow::PropRef ref |
|
||||
not hasDeleteWithName(name) and
|
||||
// and there is no deleted property with computed name
|
||||
not hasDeleteWithComputedProperty()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasDeleteWithName(string name) {
|
||||
exists(DeleteExpr del, DataFlow::PropRef ref |
|
||||
del.getOperand().flow() = ref and
|
||||
flowsTo(ref.getBase()) and
|
||||
(ref.getPropertyName() = name or not exists(ref.getPropertyName()))
|
||||
ref.getPropertyName() = name
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasDeleteWithComputedProperty() {
|
||||
exists(DeleteExpr del, DataFlow::PropRef ref |
|
||||
del.getOperand().flow() = ref and
|
||||
flowsTo(ref.getBase()) and
|
||||
not exists(ref.getPropertyName())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,16 +642,23 @@ class ClassNode extends DataFlow::SourceNode {
|
||||
*/
|
||||
FunctionNode getAStaticMethod() { result = impl.getAStaticMethod() }
|
||||
|
||||
/**
|
||||
* Gets a dataflow node that refers to the superclass of this class.
|
||||
*/
|
||||
DataFlow::Node getASuperClassNode() { result = impl.getASuperClassNode() }
|
||||
|
||||
/**
|
||||
* Gets a direct super class of this class.
|
||||
*/
|
||||
ClassNode getADirectSuperClass() {
|
||||
result.getConstructor().getAstNode() = impl
|
||||
.getASuperClassNode()
|
||||
.analyze()
|
||||
.getAValue()
|
||||
.(AbstractCallable)
|
||||
.getFunction()
|
||||
result.getAClassReference().flowsTo(getASuperClassNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a direct subclass of this class.
|
||||
*/
|
||||
final ClassNode getADirectSubClass() {
|
||||
this = result.getADirectSuperClass()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -662,6 +669,63 @@ class ClassNode extends DataFlow::SourceNode {
|
||||
or
|
||||
result = getAnInstanceMember().getReceiver()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the abstract value representing the class itself.
|
||||
*/
|
||||
AbstractValue getAbstractClassValue() {
|
||||
result = this.(AnalyzedNode).getAValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the abstract value representing an instance of this class.
|
||||
*/
|
||||
AbstractValue getAbstractInstanceValue() {
|
||||
result = AbstractInstance::of(getAstNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a dataflow node that refers to this class object.
|
||||
*/
|
||||
private DataFlow::SourceNode getAClassReference(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result.(AnalyzedNode).getAValue() = getAbstractClassValue()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = getAClassReference(t2).track(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a dataflow node that refers to this class object.
|
||||
*/
|
||||
DataFlow::SourceNode getAClassReference() {
|
||||
result = getAClassReference(DataFlow::TypeTracker::end())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a dataflow node that refers to an instance of this class.
|
||||
*/
|
||||
private DataFlow::SourceNode getAnInstanceReference(DataFlow::TypeTracker t) {
|
||||
result = getAClassReference(t.continue()).getAnInstantiation()
|
||||
or
|
||||
t.start() and
|
||||
result.(AnalyzedNode).getAValue() = getAbstractInstanceValue()
|
||||
or
|
||||
t.start() and
|
||||
result = getAReceiverNode()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = getAnInstanceReference(t2).track(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a dataflow node that refers to an instance of this class.
|
||||
*/
|
||||
DataFlow::SourceNode getAnInstanceReference() {
|
||||
result = getAnInstanceReference(DataFlow::TypeTracker::end())
|
||||
}
|
||||
}
|
||||
|
||||
module ClassNode {
|
||||
@@ -803,6 +867,9 @@ module ClassNode {
|
||||
kind = MemberKind::method() and
|
||||
result = getAPrototypeReference().getAPropertySource(name)
|
||||
or
|
||||
kind = MemberKind::method() and
|
||||
result = getConstructor().getReceiver().getAPropertySource(name)
|
||||
or
|
||||
exists(PropertyAccessor accessor |
|
||||
accessor = getAnAccessor(kind) and
|
||||
accessor.getName() = name and
|
||||
@@ -812,7 +879,10 @@ module ClassNode {
|
||||
|
||||
override FunctionNode getAnInstanceMember(MemberKind kind) {
|
||||
kind = MemberKind::method() and
|
||||
result = getAPrototypeReference().getAPropertyWrite().getRhs().getALocalSource()
|
||||
result = getAPrototypeReference().getAPropertySource()
|
||||
or
|
||||
kind = MemberKind::method() and
|
||||
result = getConstructor().getReceiver().getAPropertySource()
|
||||
or
|
||||
exists(PropertyAccessor accessor |
|
||||
accessor = getAnAccessor(kind) and
|
||||
@@ -823,7 +893,7 @@ module ClassNode {
|
||||
override FunctionNode getStaticMethod(string name) { result = getAPropertySource(name) }
|
||||
|
||||
override FunctionNode getAStaticMethod() {
|
||||
result = getAPropertyWrite().getRhs().getALocalSource()
|
||||
result = getAPropertySource()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,6 +155,13 @@ class SourceNode extends DataFlow::Node {
|
||||
result.flowsTo(getAPropertyWrite(prop).getRhs())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a source node whose value is stored in a property of this node.
|
||||
*/
|
||||
DataFlow::SourceNode getAPropertySource() {
|
||||
result.flowsTo(getAPropertyWrite().getRhs())
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL.
|
||||
*
|
||||
|
||||
@@ -97,11 +97,33 @@ private module CachedSteps {
|
||||
f = cap.getContainer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the method invoked by `invoke` resolved to a member named `name` in `cls`
|
||||
* or one of its super classes.
|
||||
*/
|
||||
cached
|
||||
predicate callResolvesToMember(DataFlow::InvokeNode invoke, DataFlow::ClassNode cls, string name) {
|
||||
invoke = cls.getAnInstanceReference().getAMethodCall(name)
|
||||
or
|
||||
exists(DataFlow::ClassNode subclass |
|
||||
callResolvesToMember(invoke, subclass, name) and
|
||||
not exists(subclass.getAnInstanceMember(name)) and
|
||||
cls = subclass.getADirectSuperClass()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `invk` may invoke `f`.
|
||||
*/
|
||||
cached
|
||||
predicate calls(DataFlow::InvokeNode invk, Function f) { f = invk.getACallee(0) }
|
||||
predicate calls(DataFlow::InvokeNode invk, Function f) {
|
||||
f = invk.getACallee(0)
|
||||
or
|
||||
exists(DataFlow::ClassNode cls, string name |
|
||||
callResolvesToMember(invk, cls, name) and
|
||||
f = cls.getInstanceMethod(name).getFunction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `invk` may invoke `f` indirectly through the given `callback` argument.
|
||||
|
||||
Reference in New Issue
Block a user