-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Python: Adopt shared type tracking library #14848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4776e9c
3b1146b
1e24de7
84aa9f1
6fc9e61
a776132
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: minorAnalysis | ||
--- | ||
* Python now makes use of the shared type tracking library, exposed as `semmle.python.dataflow.new.TypeTracking`. The existing type tracking library, `semmle.python.dataflow.new.TypeTracker`, has consequently been deprecated. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* Provides classes and predicates for simple data-flow reachability suitable | ||
* for tracking types. | ||
*/ | ||
|
||
private import internal.TypeTrackingImpl as Impl | ||
import Impl::Shared::TypeTracking<Impl::TypeTrackingInput> | ||
|
||
/** A string that may appear as the name of an attribute or access path. */ | ||
class AttributeName = Impl::TypeTrackingInput::Content; | ||
|
||
/** | ||
* A summary of the steps needed to track a value to a given dataflow node. | ||
* | ||
* This can be used to track objects that implement a certain API in order to | ||
* recognize calls to that API. Note that type-tracking does not by itself provide a | ||
* source/sink relation, that is, it may determine that a node has a given type, | ||
* but it won't determine where that type came from. | ||
* | ||
* It is recommended that all uses of this type are written in the following form, | ||
* for tracking some type `myType`: | ||
* ```ql | ||
* Node myType(TypeTracker tt) { | ||
* tt.start() and | ||
* result = < source of myType > | ||
* or | ||
* exists(TypeTracker tt2 | | ||
* tt = tt2.step(myType(tt2), result) | ||
* ) | ||
* } | ||
* | ||
* Node myType() { myType(TypeTracker::end()).flowsTo(result) } | ||
* ``` | ||
* | ||
* If you want to track individual intra-procedural steps, use `tt2.smallstep` | ||
* instead of `tt2.step`. | ||
*/ | ||
class TypeTracker extends Impl::TypeTracker { | ||
/** | ||
* Holds if this is the starting point of type tracking, and the value starts in the attribute named `attrName`. | ||
* The type tracking only ends after the attribute has been loaded. | ||
*/ | ||
predicate startInAttr(string attrName) { this.startInContent(attrName) } | ||
|
||
/** | ||
* INTERNAL. DO NOT USE. | ||
* | ||
* Gets the attribute associated with this type tracker. | ||
*/ | ||
string getAttr() { | ||
result = this.getContent().asSome() | ||
or | ||
this.getContent().isNone() and | ||
result = "" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,8 @@ class LocalSourceNode extends Node { | |
// We include all scope entry definitions, as these act as the local source within the scope they | ||
// enter. | ||
this.asCfgNode() = any(ScopeEntryDefinition def).getDefiningNode() | ||
or | ||
this instanceof ParameterNode | ||
} | ||
|
||
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ | ||
|
@@ -151,7 +153,7 @@ class LocalSourceNode extends Node { | |
* See `TypeBackTracker` for more details about how to use this. | ||
*/ | ||
pragma[inline] | ||
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) } | ||
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t = t2.step(result, this) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change makes me wonder if the QLDoc for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think the QL doc changed here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, and even if it had mentioned |
||
} | ||
|
||
/** | ||
|
@@ -238,7 +240,7 @@ private module Cached { | |
* Helper predicate for `hasLocalSource`. Removes any steps go to module variable reads, as these | ||
* are already local source nodes in their own right. | ||
*/ | ||
cached | ||
pragma[nomagic] | ||
private predicate localSourceFlowStep(Node nodeFrom, Node nodeTo) { | ||
simpleLocalFlowStep(nodeFrom, nodeTo) and | ||
not nodeTo = any(ModuleVariableNode v).getARead() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, I am surprised we did not have this before!
I am curious, did you observe test-failures from this?
Given the first case
this will only add synthetic parameter nodes (I also verified this with a quick query), but there can still be lots of those...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Me too.
The shared type tracking library (sensibly) assumes parameters to be local source nodes:
codeql/shared/typetracking/codeql/typetracking/TypeTracking.qll
Line 67 in 50b754b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah!