diff --git a/config/identical-files.json b/config/identical-files.json
index 77bee6b5097..c56fbb40f8f 100644
--- a/config/identical-files.json
+++ b/config/identical-files.json
@@ -454,10 +454,6 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
],
- "SummaryTypeTracker": [
- "python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
- "ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
- ],
"IncompleteUrlSubstringSanitization": [
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll
deleted file mode 100644
index efe7629fffc..00000000000
--- a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll
+++ /dev/null
@@ -1,412 +0,0 @@
-/**
- * Provides the implementation of type tracking steps through flow summaries.
- * To use this, you must implement the `Input` signature. You can then use the predicates in the `Output`
- * signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`.
- */
-
-/** The classes and predicates needed to generate type-tracking steps from summaries. */
-signature module Input {
- // Dataflow nodes
- class Node;
-
- // Content
- class TypeTrackerContent;
-
- class TypeTrackerContentFilter;
-
- // Relating content and filters
- /**
- * Gets a content filter to use for a `WithoutContent[content]` step, (data is not allowed to be stored in `content`)
- * or has no result if
- * the step should be treated as ordinary flow.
- *
- * `WithoutContent` is often used to perform strong updates on individual collection elements, but for
- * type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful
- * for restricting the type of an object, and in these cases we translate it to a filter.
- */
- TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content);
-
- /**
- * Gets a content filter to use for a `WithContent[content]` step, (data must be stored in `content`)
- * or has no result if
- * the step cannot be handled by type-tracking.
- *
- * `WithContent` is often used to perform strong updates on individual collection elements (or rather
- * to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive.
- * However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter.
- */
- TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content);
-
- // Summaries and their stacks
- class SummaryComponent;
-
- class SummaryComponentStack {
- SummaryComponent head();
- }
-
- /** Gets a singleton stack containing `component`. */
- SummaryComponentStack singleton(SummaryComponent component);
-
- /**
- * Gets the stack obtained by pushing `head` onto `tail`.
- */
- SummaryComponentStack push(SummaryComponent head, SummaryComponentStack tail);
-
- /** Gets a singleton stack representing a return. */
- SummaryComponent return();
-
- // Relating content to summaries
- /** Gets a summary component for content `c`. */
- SummaryComponent content(TypeTrackerContent contents);
-
- /** Gets a summary component where data is not allowed to be stored in `contents`. */
- SummaryComponent withoutContent(TypeTrackerContent contents);
-
- /** Gets a summary component where data must be stored in `contents`. */
- SummaryComponent withContent(TypeTrackerContent contents);
-
- // Callables
- class SummarizedCallable {
- predicate propagatesFlow(
- SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
- );
- }
-
- // Relating nodes to summaries
- /**
- * Gets a dataflow node respresenting the argument of `call` indicated by `arg`.
- *
- * Returns the post-update node of the argument when `isPostUpdate` is true.
- */
- Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate);
-
- /** Gets a dataflow node respresenting the parameter of `callable` indicated by `param`. */
- Node parameterOf(Node callable, SummaryComponent param);
-
- /** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */
- Node returnOf(Node callable, SummaryComponent return);
-
- // Relating callables to nodes
- /** Gets a dataflow node respresenting a call to `callable`. */
- Node callTo(SummarizedCallable callable);
-}
-
-/**
- * The predicates provided by a summary type tracker.
- * These are meant to be used in `TypeTrackerSpecific.qll`
- * inside the predicates of the same names.
- */
-signature module Output {
- /**
- * Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph.
- */
- predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo);
-
- /**
- * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
- */
- predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
-
- /**
- * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
- */
- predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
-
- /**
- * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
- */
- predicate basicLoadStoreStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
- I::TypeTrackerContent storeContent
- );
-
- /**
- * Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
- */
- predicate basicWithoutContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- );
-
- /**
- * Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
- */
- predicate basicWithContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- );
-}
-
-/**
- * Implementation of the summary type tracker, that is type tracking through flow summaries.
- */
-module SummaryFlow implements Output {
- pragma[nomagic]
- private predicate isNonLocal(I::SummaryComponent component) {
- component = I::content(_)
- or
- component = I::withContent(_)
- }
-
- pragma[nomagic]
- private predicate hasLoadSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- ) {
- callable.propagatesFlow(I::push(I::content(contents), input), output, true) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head())
- }
-
- pragma[nomagic]
- private predicate hasStoreSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- ) {
- not isNonLocal(input.head()) and
- not isNonLocal(output.head()) and
- (
- callable.propagatesFlow(input, I::push(I::content(contents), output), true)
- or
- // Allow the input to start with an arbitrary WithoutContent[X].
- // Since type-tracking only tracks one content deep, and we're about to store into another content,
- // we're already preventing the input from being in a content.
- callable
- .propagatesFlow(I::push(I::withoutContent(_), input),
- I::push(I::content(contents), output), true)
- )
- }
-
- pragma[nomagic]
- private predicate hasLoadStoreSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent loadContents,
- I::TypeTrackerContent storeContents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- ) {
- callable
- .propagatesFlow(I::push(I::content(loadContents), input),
- I::push(I::content(storeContents), output), true) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head())
- }
-
- pragma[nomagic]
- private predicate hasWithoutContentSummary(
- I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
- I::SummaryComponentStack input, I::SummaryComponentStack output
- ) {
- exists(I::TypeTrackerContent content |
- callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and
- filter = I::getFilterFromWithoutContentStep(content) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head()) and
- input != output
- )
- }
-
- pragma[nomagic]
- private predicate hasWithContentSummary(
- I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
- I::SummaryComponentStack input, I::SummaryComponentStack output
- ) {
- exists(I::TypeTrackerContent content |
- callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and
- filter = I::getFilterFromWithContentStep(content) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head()) and
- input != output
- )
- }
-
- private predicate componentLevelStep(I::SummaryComponent component) {
- exists(I::TypeTrackerContent content |
- component = I::withoutContent(content) and
- not exists(I::getFilterFromWithoutContentStep(content))
- )
- }
-
- /**
- * Gets a data flow `I::Node` corresponding an argument or return value of `call`,
- * as specified by `component`. `isOutput` indicates whether the node represents
- * an output node or an input node.
- */
- bindingset[call, component]
- private I::Node evaluateSummaryComponentLocal(
- I::Node call, I::SummaryComponent component, boolean isOutput
- ) {
- result = I::argumentOf(call, component, isOutput)
- or
- component = I::return() and
- result = call and
- isOutput = true
- }
-
- /**
- * Holds if `callable` is relevant for type-tracking and we therefore want `stack` to
- * be evaluated locally at its call sites.
- */
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStack(
- I::SummarizedCallable callable, I::SummaryComponentStack stack
- ) {
- exists(I::callTo(callable)) and
- (
- callable.propagatesFlow(stack, _, true)
- or
- callable.propagatesFlow(_, stack, true)
- or
- // include store summaries as they may skip an initial step at the input
- hasStoreSummary(callable, _, stack, _)
- )
- or
- dependsOnSummaryComponentStackCons(callable, _, stack)
- }
-
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStackCons(
- I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail
- ) {
- dependsOnSummaryComponentStack(callable, I::push(head, tail))
- }
-
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStackConsLocal(
- I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail
- ) {
- dependsOnSummaryComponentStackCons(callable, head, tail) and
- not isNonLocal(head)
- }
-
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStackLeaf(
- I::SummarizedCallable callable, I::SummaryComponent leaf
- ) {
- dependsOnSummaryComponentStack(callable, I::singleton(leaf))
- }
-
- /**
- * Gets a data flow I::Node corresponding to the local input or output of `call`
- * identified by `stack`, if possible.
- */
- pragma[nomagic]
- private I::Node evaluateSummaryComponentStackLocal(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack stack, boolean isOutput
- ) {
- exists(I::SummaryComponent component |
- dependsOnSummaryComponentStackLeaf(callable, component) and
- stack = I::singleton(component) and
- call = I::callTo(callable) and
- result = evaluateSummaryComponentLocal(call, component, isOutput)
- )
- or
- exists(
- I::Node prev, I::SummaryComponent head, I::SummaryComponentStack tail, boolean isOutput0
- |
- prev = evaluateSummaryComponentStackLocal(callable, call, tail, isOutput0) and
- dependsOnSummaryComponentStackConsLocal(callable, pragma[only_bind_into](head),
- pragma[only_bind_out](tail)) and
- stack = I::push(pragma[only_bind_out](head), pragma[only_bind_out](tail))
- |
- // `Parameter[X]` is only allowed in the output of flow summaries (hence `isOutput = true`),
- // however the target of the parameter (e.g. `Argument[Y].Parameter[X]`) should be fetched
- // not from a post-update argument node (hence `isOutput0 = false`)
- result = I::parameterOf(prev, head) and
- isOutput0 = false and
- isOutput = true
- or
- // `ReturnValue` is only allowed in the input of flow summaries (hence `isOutput = false`),
- // and the target of the return value (e.g. `Argument[X].ReturnValue`) should be fetched not
- // from a post-update argument node (hence `isOutput0 = false`)
- result = I::returnOf(prev, head) and
- isOutput0 = false and
- isOutput = false
- or
- componentLevelStep(head) and
- result = prev and
- isOutput = isOutput0
- )
- }
-
- // Implement Output
- predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- callable.propagatesFlow(input, output, true) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasLoadSummary(callable, content, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasStoreSummary(callable, content, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicLoadStoreStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
- I::TypeTrackerContent storeContent
- ) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasLoadStoreSummary(callable, loadContent, storeContent, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicWithoutContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- ) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasWithoutContentSummary(callable, filter, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicWithContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- ) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasWithContentSummary(callable, filter, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-}
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
index 6e1482ae74c..4c3538d75f7 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
@@ -5,7 +5,7 @@ private import python
private import semmle.python.internal.CachedStages
private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
-private import SummaryTypeTracker as SummaryTypeTracker
+private import codeql.typetracking.internal.SummaryTypeTracker as SummaryTypeTracker
private import semmle.python.dataflow.new.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch
@@ -14,13 +14,13 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
class Node = DataFlowPublic::Node;
// Content
- class TypeTrackerContent = DataFlowPublic::ContentSet;
+ class Content = DataFlowPublic::ContentSet;
- class TypeTrackerContentFilter = TypeTrackingInput::ContentFilter;
+ class ContentFilter = TypeTrackingInput::ContentFilter;
- TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) { none() }
+ ContentFilter getFilterFromWithoutContentStep(Content content) { none() }
- TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) { none() }
+ ContentFilter getFilterFromWithContentStep(Content content) { none() }
// Callables
class SummarizedCallable = FlowSummaryImpl::Private::SummarizedCallableImpl;
@@ -37,9 +37,9 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
// Relating content to summaries
predicate content = FlowSummaryImpl::Private::SummaryComponent::content/1;
- SummaryComponent withoutContent(TypeTrackerContent contents) { none() }
+ SummaryComponent withoutContent(Content contents) { none() }
- SummaryComponent withContent(TypeTrackerContent contents) { none() }
+ SummaryComponent withContent(Content contents) { none() }
predicate return = FlowSummaryImpl::Private::SummaryComponent::return/0;
diff --git a/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll
deleted file mode 100644
index efe7629fffc..00000000000
--- a/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll
+++ /dev/null
@@ -1,412 +0,0 @@
-/**
- * Provides the implementation of type tracking steps through flow summaries.
- * To use this, you must implement the `Input` signature. You can then use the predicates in the `Output`
- * signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`.
- */
-
-/** The classes and predicates needed to generate type-tracking steps from summaries. */
-signature module Input {
- // Dataflow nodes
- class Node;
-
- // Content
- class TypeTrackerContent;
-
- class TypeTrackerContentFilter;
-
- // Relating content and filters
- /**
- * Gets a content filter to use for a `WithoutContent[content]` step, (data is not allowed to be stored in `content`)
- * or has no result if
- * the step should be treated as ordinary flow.
- *
- * `WithoutContent` is often used to perform strong updates on individual collection elements, but for
- * type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful
- * for restricting the type of an object, and in these cases we translate it to a filter.
- */
- TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content);
-
- /**
- * Gets a content filter to use for a `WithContent[content]` step, (data must be stored in `content`)
- * or has no result if
- * the step cannot be handled by type-tracking.
- *
- * `WithContent` is often used to perform strong updates on individual collection elements (or rather
- * to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive.
- * However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter.
- */
- TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content);
-
- // Summaries and their stacks
- class SummaryComponent;
-
- class SummaryComponentStack {
- SummaryComponent head();
- }
-
- /** Gets a singleton stack containing `component`. */
- SummaryComponentStack singleton(SummaryComponent component);
-
- /**
- * Gets the stack obtained by pushing `head` onto `tail`.
- */
- SummaryComponentStack push(SummaryComponent head, SummaryComponentStack tail);
-
- /** Gets a singleton stack representing a return. */
- SummaryComponent return();
-
- // Relating content to summaries
- /** Gets a summary component for content `c`. */
- SummaryComponent content(TypeTrackerContent contents);
-
- /** Gets a summary component where data is not allowed to be stored in `contents`. */
- SummaryComponent withoutContent(TypeTrackerContent contents);
-
- /** Gets a summary component where data must be stored in `contents`. */
- SummaryComponent withContent(TypeTrackerContent contents);
-
- // Callables
- class SummarizedCallable {
- predicate propagatesFlow(
- SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
- );
- }
-
- // Relating nodes to summaries
- /**
- * Gets a dataflow node respresenting the argument of `call` indicated by `arg`.
- *
- * Returns the post-update node of the argument when `isPostUpdate` is true.
- */
- Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate);
-
- /** Gets a dataflow node respresenting the parameter of `callable` indicated by `param`. */
- Node parameterOf(Node callable, SummaryComponent param);
-
- /** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */
- Node returnOf(Node callable, SummaryComponent return);
-
- // Relating callables to nodes
- /** Gets a dataflow node respresenting a call to `callable`. */
- Node callTo(SummarizedCallable callable);
-}
-
-/**
- * The predicates provided by a summary type tracker.
- * These are meant to be used in `TypeTrackerSpecific.qll`
- * inside the predicates of the same names.
- */
-signature module Output {
- /**
- * Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph.
- */
- predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo);
-
- /**
- * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
- */
- predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
-
- /**
- * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
- */
- predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
-
- /**
- * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
- */
- predicate basicLoadStoreStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
- I::TypeTrackerContent storeContent
- );
-
- /**
- * Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
- */
- predicate basicWithoutContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- );
-
- /**
- * Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
- */
- predicate basicWithContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- );
-}
-
-/**
- * Implementation of the summary type tracker, that is type tracking through flow summaries.
- */
-module SummaryFlow implements Output {
- pragma[nomagic]
- private predicate isNonLocal(I::SummaryComponent component) {
- component = I::content(_)
- or
- component = I::withContent(_)
- }
-
- pragma[nomagic]
- private predicate hasLoadSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- ) {
- callable.propagatesFlow(I::push(I::content(contents), input), output, true) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head())
- }
-
- pragma[nomagic]
- private predicate hasStoreSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- ) {
- not isNonLocal(input.head()) and
- not isNonLocal(output.head()) and
- (
- callable.propagatesFlow(input, I::push(I::content(contents), output), true)
- or
- // Allow the input to start with an arbitrary WithoutContent[X].
- // Since type-tracking only tracks one content deep, and we're about to store into another content,
- // we're already preventing the input from being in a content.
- callable
- .propagatesFlow(I::push(I::withoutContent(_), input),
- I::push(I::content(contents), output), true)
- )
- }
-
- pragma[nomagic]
- private predicate hasLoadStoreSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent loadContents,
- I::TypeTrackerContent storeContents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- ) {
- callable
- .propagatesFlow(I::push(I::content(loadContents), input),
- I::push(I::content(storeContents), output), true) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head())
- }
-
- pragma[nomagic]
- private predicate hasWithoutContentSummary(
- I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
- I::SummaryComponentStack input, I::SummaryComponentStack output
- ) {
- exists(I::TypeTrackerContent content |
- callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and
- filter = I::getFilterFromWithoutContentStep(content) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head()) and
- input != output
- )
- }
-
- pragma[nomagic]
- private predicate hasWithContentSummary(
- I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
- I::SummaryComponentStack input, I::SummaryComponentStack output
- ) {
- exists(I::TypeTrackerContent content |
- callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and
- filter = I::getFilterFromWithContentStep(content) and
- not isNonLocal(input.head()) and
- not isNonLocal(output.head()) and
- input != output
- )
- }
-
- private predicate componentLevelStep(I::SummaryComponent component) {
- exists(I::TypeTrackerContent content |
- component = I::withoutContent(content) and
- not exists(I::getFilterFromWithoutContentStep(content))
- )
- }
-
- /**
- * Gets a data flow `I::Node` corresponding an argument or return value of `call`,
- * as specified by `component`. `isOutput` indicates whether the node represents
- * an output node or an input node.
- */
- bindingset[call, component]
- private I::Node evaluateSummaryComponentLocal(
- I::Node call, I::SummaryComponent component, boolean isOutput
- ) {
- result = I::argumentOf(call, component, isOutput)
- or
- component = I::return() and
- result = call and
- isOutput = true
- }
-
- /**
- * Holds if `callable` is relevant for type-tracking and we therefore want `stack` to
- * be evaluated locally at its call sites.
- */
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStack(
- I::SummarizedCallable callable, I::SummaryComponentStack stack
- ) {
- exists(I::callTo(callable)) and
- (
- callable.propagatesFlow(stack, _, true)
- or
- callable.propagatesFlow(_, stack, true)
- or
- // include store summaries as they may skip an initial step at the input
- hasStoreSummary(callable, _, stack, _)
- )
- or
- dependsOnSummaryComponentStackCons(callable, _, stack)
- }
-
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStackCons(
- I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail
- ) {
- dependsOnSummaryComponentStack(callable, I::push(head, tail))
- }
-
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStackConsLocal(
- I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail
- ) {
- dependsOnSummaryComponentStackCons(callable, head, tail) and
- not isNonLocal(head)
- }
-
- pragma[nomagic]
- private predicate dependsOnSummaryComponentStackLeaf(
- I::SummarizedCallable callable, I::SummaryComponent leaf
- ) {
- dependsOnSummaryComponentStack(callable, I::singleton(leaf))
- }
-
- /**
- * Gets a data flow I::Node corresponding to the local input or output of `call`
- * identified by `stack`, if possible.
- */
- pragma[nomagic]
- private I::Node evaluateSummaryComponentStackLocal(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack stack, boolean isOutput
- ) {
- exists(I::SummaryComponent component |
- dependsOnSummaryComponentStackLeaf(callable, component) and
- stack = I::singleton(component) and
- call = I::callTo(callable) and
- result = evaluateSummaryComponentLocal(call, component, isOutput)
- )
- or
- exists(
- I::Node prev, I::SummaryComponent head, I::SummaryComponentStack tail, boolean isOutput0
- |
- prev = evaluateSummaryComponentStackLocal(callable, call, tail, isOutput0) and
- dependsOnSummaryComponentStackConsLocal(callable, pragma[only_bind_into](head),
- pragma[only_bind_out](tail)) and
- stack = I::push(pragma[only_bind_out](head), pragma[only_bind_out](tail))
- |
- // `Parameter[X]` is only allowed in the output of flow summaries (hence `isOutput = true`),
- // however the target of the parameter (e.g. `Argument[Y].Parameter[X]`) should be fetched
- // not from a post-update argument node (hence `isOutput0 = false`)
- result = I::parameterOf(prev, head) and
- isOutput0 = false and
- isOutput = true
- or
- // `ReturnValue` is only allowed in the input of flow summaries (hence `isOutput = false`),
- // and the target of the return value (e.g. `Argument[X].ReturnValue`) should be fetched not
- // from a post-update argument node (hence `isOutput0 = false`)
- result = I::returnOf(prev, head) and
- isOutput0 = false and
- isOutput = false
- or
- componentLevelStep(head) and
- result = prev and
- isOutput = isOutput0
- )
- }
-
- // Implement Output
- predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- callable.propagatesFlow(input, output, true) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasLoadSummary(callable, content, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasStoreSummary(callable, content, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicLoadStoreStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
- I::TypeTrackerContent storeContent
- ) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasLoadStoreSummary(callable, loadContent, storeContent, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicWithoutContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- ) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasWithoutContentSummary(callable, filter, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-
- predicate basicWithContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- ) {
- exists(
- I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
- I::SummaryComponentStack output
- |
- hasWithContentSummary(callable, filter, pragma[only_bind_into](input),
- pragma[only_bind_into](output)) and
- call = I::callTo(callable) and
- nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input, false) and
- nodeTo = evaluateSummaryComponentStackLocal(callable, call, output, true)
- )
- }
-}
diff --git a/ruby/ql/lib/codeql/ruby/typetracking/internal/TypeTrackingImpl.qll b/ruby/ql/lib/codeql/ruby/typetracking/internal/TypeTrackingImpl.qll
index 13f6c1de149..750c96ef723 100644
--- a/ruby/ql/lib/codeql/ruby/typetracking/internal/TypeTrackingImpl.qll
+++ b/ruby/ql/lib/codeql/ruby/typetracking/internal/TypeTrackingImpl.qll
@@ -3,7 +3,7 @@ import codeql.typetracking.internal.TypeTrackingImpl as SharedImpl
private import codeql.ruby.AST
private import codeql.ruby.CFG as Cfg
private import Cfg::CfgNodes
-private import SummaryTypeTracker as SummaryTypeTracker
+private import codeql.typetracking.internal.SummaryTypeTracker as SummaryTypeTracker
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
private import codeql.ruby.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
@@ -133,11 +133,11 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
class Node = DataFlow::Node;
// Content
- class TypeTrackerContent = DataFlowPublic::ContentSet;
+ class Content = DataFlowPublic::ContentSet;
- class TypeTrackerContentFilter = TypeTrackingInput::ContentFilter;
+ class ContentFilter = TypeTrackingInput::ContentFilter;
- TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) {
+ ContentFilter getFilterFromWithoutContentStep(Content content) {
(
content.isAnyElement()
or
@@ -150,7 +150,7 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
result = MkElementFilter()
}
- TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) {
+ ContentFilter getFilterFromWithContentStep(Content content) {
(
content.isAnyElement()
or
diff --git a/shared/typetracking/codeql/typetracking/internal/SummaryTypeTracker.qll b/shared/typetracking/codeql/typetracking/internal/SummaryTypeTracker.qll
index efe7629fffc..b942446d43b 100644
--- a/shared/typetracking/codeql/typetracking/internal/SummaryTypeTracker.qll
+++ b/shared/typetracking/codeql/typetracking/internal/SummaryTypeTracker.qll
@@ -10,9 +10,9 @@ signature module Input {
class Node;
// Content
- class TypeTrackerContent;
+ class Content;
- class TypeTrackerContentFilter;
+ class ContentFilter;
// Relating content and filters
/**
@@ -24,7 +24,7 @@ signature module Input {
* type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful
* for restricting the type of an object, and in these cases we translate it to a filter.
*/
- TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content);
+ ContentFilter getFilterFromWithoutContentStep(Content content);
/**
* Gets a content filter to use for a `WithContent[content]` step, (data must be stored in `content`)
@@ -35,7 +35,7 @@ signature module Input {
* to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive.
* However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter.
*/
- TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content);
+ ContentFilter getFilterFromWithContentStep(Content content);
// Summaries and their stacks
class SummaryComponent;
@@ -57,13 +57,13 @@ signature module Input {
// Relating content to summaries
/** Gets a summary component for content `c`. */
- SummaryComponent content(TypeTrackerContent contents);
+ SummaryComponent content(Content contents);
/** Gets a summary component where data is not allowed to be stored in `contents`. */
- SummaryComponent withoutContent(TypeTrackerContent contents);
+ SummaryComponent withoutContent(Content contents);
/** Gets a summary component where data must be stored in `contents`. */
- SummaryComponent withContent(TypeTrackerContent contents);
+ SummaryComponent withContent(Content contents);
// Callables
class SummarizedCallable {
@@ -105,34 +105,29 @@ signature module Output {
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
- predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
+ predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::Content content);
/**
* Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
*/
- predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
+ predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::Content content);
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
predicate basicLoadStoreStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
- I::TypeTrackerContent storeContent
+ I::Node nodeFrom, I::Node nodeTo, I::Content loadContent, I::Content storeContent
);
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
*/
- predicate basicWithoutContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- );
+ predicate basicWithoutContentStep(I::Node nodeFrom, I::Node nodeTo, I::ContentFilter filter);
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
*/
- predicate basicWithContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- );
+ predicate basicWithContentStep(I::Node nodeFrom, I::Node nodeTo, I::ContentFilter filter);
}
/**
@@ -148,7 +143,7 @@ module SummaryFlow implements Output {
pragma[nomagic]
private predicate hasLoadSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
+ I::SummarizedCallable callable, I::Content contents, I::SummaryComponentStack input,
I::SummaryComponentStack output
) {
callable.propagatesFlow(I::push(I::content(contents), input), output, true) and
@@ -158,7 +153,7 @@ module SummaryFlow implements Output {
pragma[nomagic]
private predicate hasStoreSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
+ I::SummarizedCallable callable, I::Content contents, I::SummaryComponentStack input,
I::SummaryComponentStack output
) {
not isNonLocal(input.head()) and
@@ -177,9 +172,8 @@ module SummaryFlow implements Output {
pragma[nomagic]
private predicate hasLoadStoreSummary(
- I::SummarizedCallable callable, I::TypeTrackerContent loadContents,
- I::TypeTrackerContent storeContents, I::SummaryComponentStack input,
- I::SummaryComponentStack output
+ I::SummarizedCallable callable, I::Content loadContents, I::Content storeContents,
+ I::SummaryComponentStack input, I::SummaryComponentStack output
) {
callable
.propagatesFlow(I::push(I::content(loadContents), input),
@@ -190,10 +184,10 @@ module SummaryFlow implements Output {
pragma[nomagic]
private predicate hasWithoutContentSummary(
- I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
- I::SummaryComponentStack input, I::SummaryComponentStack output
+ I::SummarizedCallable callable, I::ContentFilter filter, I::SummaryComponentStack input,
+ I::SummaryComponentStack output
) {
- exists(I::TypeTrackerContent content |
+ exists(I::Content content |
callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and
filter = I::getFilterFromWithoutContentStep(content) and
not isNonLocal(input.head()) and
@@ -204,10 +198,10 @@ module SummaryFlow implements Output {
pragma[nomagic]
private predicate hasWithContentSummary(
- I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
- I::SummaryComponentStack input, I::SummaryComponentStack output
+ I::SummarizedCallable callable, I::ContentFilter filter, I::SummaryComponentStack input,
+ I::SummaryComponentStack output
) {
- exists(I::TypeTrackerContent content |
+ exists(I::Content content |
callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and
filter = I::getFilterFromWithContentStep(content) and
not isNonLocal(input.head()) and
@@ -217,7 +211,7 @@ module SummaryFlow implements Output {
}
private predicate componentLevelStep(I::SummaryComponent component) {
- exists(I::TypeTrackerContent content |
+ exists(I::Content content |
component = I::withoutContent(content) and
not exists(I::getFilterFromWithoutContentStep(content))
)
@@ -338,7 +332,7 @@ module SummaryFlow implements Output {
)
}
- predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
+ predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::Content content) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
@@ -351,7 +345,7 @@ module SummaryFlow implements Output {
)
}
- predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
+ predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::Content content) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
@@ -365,8 +359,7 @@ module SummaryFlow implements Output {
}
predicate basicLoadStoreStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
- I::TypeTrackerContent storeContent
+ I::Node nodeFrom, I::Node nodeTo, I::Content loadContent, I::Content storeContent
) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
@@ -380,9 +373,7 @@ module SummaryFlow implements Output {
)
}
- predicate basicWithoutContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- ) {
+ predicate basicWithoutContentStep(I::Node nodeFrom, I::Node nodeTo, I::ContentFilter filter) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
@@ -395,9 +386,7 @@ module SummaryFlow implements Output {
)
}
- predicate basicWithContentStep(
- I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
- ) {
+ predicate basicWithContentStep(I::Node nodeFrom, I::Node nodeTo, I::ContentFilter filter) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output