all: use my script to delete outdated deprecations

This commit is contained in:
erik-krogh
2025-01-27 18:15:12 +01:00
parent 253ccd1210
commit 34f5f61a10
121 changed files with 4 additions and 4910 deletions

View File

@@ -264,12 +264,6 @@ module API {
pragma[inline_late]
DataFlow::CallNode asCall() { this = Impl::MkMethodAccessNode(result) }
/**
* DEPRECATED. Use `asCall()` instead.
*/
pragma[inline]
deprecated DataFlow::CallNode getCallNode() { this = Impl::MkMethodAccessNode(result) }
/**
* Gets a module or class that descends from the module or class referenced by this API node.
*/
@@ -607,104 +601,10 @@ module API {
*/
string toString() { none() }
/**
* Gets a node representing a (direct or indirect) subclass of the class represented by this node.
* ```rb
* class A; end
* class B < A; end
* class C < B; end
* ```
* In the example above, `getMember("A").getASubclass()` will return uses of `A`, `B` and `C`.
*/
pragma[inline]
deprecated Node getASubclass() { result = this }
/**
* Gets a node representing a direct subclass of the class represented by this node.
* ```rb
* class A; end
* class B < A; end
* class C < B; end
* ```
* In the example above, `getMember("A").getAnImmediateSubclass()` will return uses of `B` only.
*/
pragma[inline]
deprecated Node getAnImmediateSubclass() {
result = this.asModule().getAnImmediateDescendent().trackModule()
}
/** DEPRECATED. This predicate has been renamed to `getAValueReachableFromSource()`. */
deprecated DataFlow::Node getAUse() { result = this.getAValueReachableFromSource() }
/** DEPRECATED. This predicate has been renamed to `asSource()`. */
deprecated DataFlow::LocalSourceNode getAnImmediateUse() { result = this.asSource() }
/** DEPRECATED. This predicate has been renamed to `asSink()`. */
deprecated DataFlow::Node getARhs() { result = this.asSink() }
/** DEPRECATED. This predicate has been renamed to `getAValueReachingSink()`. */
deprecated DataFlow::Node getAValueReachingRhs() { result = this.getAValueReachingSink() }
/**
* DEPRECATED. API graph nodes are no longer associated with specific paths.
*
* Gets a string representation of the lexicographically least among all shortest access paths
* from the root to this node.
*/
deprecated string getPath() { none() }
/**
* DEPRECATED. Use label-specific predicates in this class, such as `getMember`, instead of using `getASuccessor`.
*
* Gets a node such that there is an edge in the API graph between this node and the other
* one, and that edge is labeled with `lbl`.
*/
pragma[inline]
deprecated Node getASuccessor(Label::ApiLabel lbl) {
labelledEdge(this.getAnEpsilonSuccessor(), lbl, result)
}
/**
* DEPRECATED. API graphs no longer support backward traversal of edges. If possible use `.backtrack()` to get
* a node intended for backtracking.
*
* Gets a node such that there is an edge in the API graph between that other node and
* this one, and that edge is labeled with `lbl`
*/
deprecated Node getAPredecessor(Label::ApiLabel lbl) { this = result.getASuccessor(lbl) }
/**
* DEPRECATED. API graphs no longer support backward traversal of edges. If possible use `.backtrack()` to get
* a node intended for backtracking.
*
* Gets a node such that there is an edge in the API graph between this node and the other
* one.
*/
deprecated Node getAPredecessor() { result = this.getAPredecessor(_) }
/**
* Gets a node such that there is an edge in the API graph between that other node and
* this one.
*/
pragma[inline]
deprecated Node getASuccessor() { result = this.getASuccessor(_) }
/** DEPRECATED. API graphs are no longer associated with a depth. */
deprecated int getDepth() { none() }
pragma[inline]
private Node getAnEpsilonSuccessor() { result = getAnEpsilonSuccessorInline(this) }
}
/** DEPRECATED. Use `API::root()` to access the root node. */
deprecated class Root = RootNode;
/** DEPRECATED. A node corresponding to the use of an API component. */
deprecated class Use = ForwardNode;
/** DEPRECATED. A node corresponding to a value escaping into an API component. */
deprecated class Def = SinkNode;
/** The root node of an API graph. */
private class RootNode extends Node, Impl::MkRoot {
override string toString() { result = "Root()" }
@@ -1327,270 +1227,4 @@ module API {
node = MkMethodAccessNode(entry.getACall())
}
}
/**
* Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`.
*/
pragma[nomagic]
deprecated private predicate labelledEdge(Node pred, Label::ApiLabel lbl, Node succ) {
exists(string name |
Impl::memberEdge(pred, name, succ) and
lbl = Label::member(name)
)
or
exists(string name |
Impl::methodEdge(pred, name, succ) and
lbl = Label::method(name)
)
or
exists(DataFlow::Content content |
Impl::contentEdge(pred, content, succ) and
lbl = Label::content(content)
)
or
exists(DataFlowDispatch::ParameterPosition pos |
Impl::parameterEdge(pred, pos, succ) and
lbl = Label::getLabelFromParameterPosition(pos)
)
or
exists(DataFlowDispatch::ArgumentPosition pos |
Impl::argumentEdge(pred, pos, succ) and
lbl = Label::getLabelFromArgumentPosition(pos)
)
or
Impl::instanceEdge(pred, succ) and
lbl = Label::instance()
or
Impl::returnEdge(pred, succ) and
lbl = Label::return()
or
exists(EntryPoint entry |
Impl::entryPointEdge(entry, succ) and
pred = root() and
lbl = Label::entryPoint(entry)
)
}
/**
* DEPRECATED. Treating the API graph as an explicit labelled graph is deprecated - instead use the methods on `API:Node` directly.
*
* Provides classes modeling the various edges (labels) in the API graph.
*/
deprecated module Label {
/** All the possible labels in the API graph. */
private newtype TLabel =
MkLabelMember(string member) { member = any(ConstantReadAccess a).getName() } or
MkLabelMethod(string m) { m = any(DataFlow::CallNode c).getMethodName() } or
MkLabelReturn() or
MkLabelInstance() or
MkLabelKeywordParameter(string name) {
any(DataFlowDispatch::ArgumentPosition arg).isKeyword(name)
or
any(DataFlowDispatch::ParameterPosition arg).isKeyword(name)
} or
MkLabelParameter(int n) {
any(DataFlowDispatch::ArgumentPosition c).isPositional(n)
or
any(DataFlowDispatch::ParameterPosition c).isPositional(n)
} or
MkLabelBlockParameter() or
MkLabelEntryPoint(EntryPoint name) or
MkLabelContent(DataFlow::Content content)
/** A label in the API-graph */
class ApiLabel extends TLabel {
/** Gets a string representation of this label. */
string toString() { result = "???" }
}
private import LabelImpl
private module LabelImpl {
private import Impl
/** A label for a member, for example a constant. */
class LabelMember extends ApiLabel, MkLabelMember {
private string member;
LabelMember() { this = MkLabelMember(member) }
/** Gets the member name associated with this label. */
string getMember() { result = member }
override string toString() { result = "getMember(\"" + member + "\")" }
}
/** A label for a method. */
class LabelMethod extends ApiLabel, MkLabelMethod {
private string method;
LabelMethod() { this = MkLabelMethod(method) }
/** Gets the method name associated with this label. */
string getMethod() { result = method }
override string toString() { result = "getMethod(\"" + method + "\")" }
}
/** A label for the return value of a method. */
class LabelReturn extends ApiLabel, MkLabelReturn {
override string toString() { result = "getReturn()" }
}
/** A label for getting instances of a module/class. */
class LabelInstance extends ApiLabel, MkLabelInstance {
override string toString() { result = "getInstance()" }
}
/** A label for a keyword parameter. */
class LabelKeywordParameter extends ApiLabel, MkLabelKeywordParameter {
private string name;
LabelKeywordParameter() { this = MkLabelKeywordParameter(name) }
/** Gets the name of the keyword parameter associated with this label. */
string getName() { result = name }
override string toString() { result = "getKeywordParameter(\"" + name + "\")" }
}
/** A label for a parameter. */
class LabelParameter extends ApiLabel, MkLabelParameter {
private int n;
LabelParameter() { this = MkLabelParameter(n) }
/** Gets the parameter number associated with this label. */
int getIndex() { result = n }
override string toString() { result = "getParameter(" + n + ")" }
}
/** A label for a block parameter. */
class LabelBlockParameter extends ApiLabel, MkLabelBlockParameter {
override string toString() { result = "getBlock()" }
}
/** A label from the root node to a custom entry point. */
class LabelEntryPoint extends ApiLabel, MkLabelEntryPoint {
private API::EntryPoint name;
LabelEntryPoint() { this = MkLabelEntryPoint(name) }
override string toString() { result = "entryPoint(\"" + name + "\")" }
/** Gets the name of the entry point. */
API::EntryPoint getName() { result = name }
}
/** A label representing contents of an object. */
class LabelContent extends ApiLabel, MkLabelContent {
private DataFlow::Content content;
LabelContent() { this = MkLabelContent(content) }
override string toString() {
result = "getContent(" + content.toString().replaceAll(" ", "_") + ")"
}
/** Gets the content represented by this label. */
DataFlow::Content getContent() { result = content }
}
}
/** Gets the `member` edge label for member `m`. */
LabelMember member(string m) { result.getMember() = m }
/** Gets the `method` edge label. */
LabelMethod method(string m) { result.getMethod() = m }
/** Gets the `return` edge label. */
LabelReturn return() { any() }
/** Gets the `instance` edge label. */
LabelInstance instance() { any() }
/** Gets the label representing the given keyword argument/parameter. */
LabelKeywordParameter keywordParameter(string name) { result.getName() = name }
/** Gets the label representing the `n`th positional argument/parameter. */
LabelParameter parameter(int n) { result.getIndex() = n }
/** Gets the label representing the block argument/parameter. */
LabelBlockParameter blockParameter() { any() }
/** Gets the label for the edge from the root node to a custom entry point of the given name. */
LabelEntryPoint entryPoint(API::EntryPoint name) { result.getName() = name }
/** Gets a label representing the given content. */
LabelContent content(DataFlow::Content content) { result.getContent() = content }
/** Gets the API graph label corresponding to the given argument position. */
Label::ApiLabel getLabelFromArgumentPosition(DataFlowDispatch::ArgumentPosition pos) {
exists(int n |
pos.isPositional(n) and
result = Label::parameter(n)
)
or
exists(string name |
pos.isKeyword(name) and
result = Label::keywordParameter(name)
)
or
pos.isBlock() and
result = Label::blockParameter()
or
pos.isAny() and
(
result = Label::parameter(_)
or
result = Label::keywordParameter(_)
or
result = Label::blockParameter()
// NOTE: `self` should NOT be included, as described in the QLDoc for `isAny()`
)
or
pos.isAnyNamed() and
result = Label::keywordParameter(_)
//
// Note: there is currently no API graph label for `self`.
// It was omitted since in practice it means going back to where you came from.
// For example, `base.getMethod("foo").getSelf()` would just be `base`.
// However, it's possible we'll need it later, for identifying `self` parameters or post-update nodes.
}
/** Gets the API graph label corresponding to the given parameter position. */
Label::ApiLabel getLabelFromParameterPosition(DataFlowDispatch::ParameterPosition pos) {
exists(int n |
pos.isPositional(n) and
result = Label::parameter(n)
)
or
exists(string name |
pos.isKeyword(name) and
result = Label::keywordParameter(name)
)
or
pos.isBlock() and
result = Label::blockParameter()
or
pos.isAny() and
(
result = Label::parameter(_)
or
result = Label::keywordParameter(_)
or
result = Label::blockParameter()
// NOTE: `self` should NOT be included, as described in the QLDoc for `isAny()`
)
or
pos.isAnyNamed() and
result = Label::keywordParameter(_)
//
// Note: there is currently no API graph label for `self`.
// It was omitted since in practice it means going back to where you came from.
// For example, `base.getMethod("foo").getSelf()` would just be `base`.
// However, it's possible we'll need it later, for identifying `self` parameters or post-update nodes.
}
}
}

View File

@@ -200,13 +200,6 @@ module ExprNodes {
override LhsExpr getExpr() { result = super.getExpr() }
/**
* DEPRECATED: use `getVariable` instead.
*
* Gets a variable used in (or introduced by) this LHS.
*/
deprecated Variable getAVariable() { result = e.(VariableAccess).getVariable() }
/** Gets the variable used in (or introduced by) this LHS. */
Variable getVariable() { result = e.(VariableAccess).getVariable() }
}

View File

@@ -635,8 +635,7 @@ private module Cached {
} or
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
type = any(Content::KnownElementContent content).getIndex().getValueType()
} or
deprecated TNoContentSet() // Only used by type-tracking
}
cached
class TContentSet =

View File

@@ -1284,13 +1284,6 @@ class LhsExprNode extends ExprNode {
/** Gets the underlying AST node as a `LhsExpr`. */
LhsExpr asLhsExprAstNode() { result = lhsExprCfgNode.getExpr() }
/**
* DEPRECATED: use `getVariable` instead.
*
* Gets a variable used in (or introduced by) this LHS.
*/
deprecated Variable getAVariable() { result = lhsExprCfgNode.getAVariable() }
/** Gets the variable used in (or introduced by) this LHS. */
Variable getVariable() { result = lhsExprCfgNode.getVariable() }
}

View File

@@ -106,71 +106,10 @@ class ActiveRecordModelClass extends ClassDeclaration {
// Gets the class declaration for this class and all of its super classes
private ModuleBase getAllClassDeclarations() { result = cls.getAnAncestor().getADeclaration() }
/**
* Gets methods defined in this class that may access a field from the database.
*/
deprecated Method getAPotentialFieldAccessMethod() {
// It's a method on this class or one of its super classes
result = this.getAllClassDeclarations().getAMethod() and
// There is a value that can be returned by this method which may include field data
exists(DataFlow::Node returned, ActiveRecordInstanceMethodCall cNode, MethodCall c |
exprNodeReturnedFrom(returned, result) and
cNode.flowsTo(returned) and
c = cNode.asExpr().getExpr()
|
// The referenced method is not built-in, and...
not isBuiltInMethodForActiveRecordModelInstance(c.getMethodName()) and
(
// ...The receiver does not have a matching method definition, or...
not exists(
cNode.getInstance().getClass().getAllClassDeclarations().getMethod(c.getMethodName())
)
or
// ...the called method can access a field
c.getATarget() = cNode.getInstance().getClass().getAPotentialFieldAccessMethod()
)
)
}
/** Gets the class as a `DataFlow::ClassNode`. */
DataFlow::ClassNode getClassNode() { result = cls }
}
/**
* Gets a potential reference to an ActiveRecord class object.
*/
deprecated private API::Node getAnActiveRecordModelClassRef() {
result = any(ActiveRecordModelClass cls).getClassNode().trackModule()
or
// For methods with an unknown call target, assume this might be a database field, thus returning another ActiveRecord object.
// In this case we do not know which class it belongs to, which is why this predicate can't associate the reference with a specific class.
result = getAnUnknownActiveRecordModelClassCall().getReturn()
}
/**
* Gets a call performed on an ActiveRecord class object, without a known call target in the codebase.
*/
deprecated private API::MethodAccessNode getAnUnknownActiveRecordModelClassCall() {
result = getAnActiveRecordModelClassRef().getMethod(_) and
result.asCall().asExpr().getExpr() instanceof UnknownMethodCall
}
/**
* DEPRECATED. Use `ActiveRecordModelClass.getClassNode().trackModule().getMethod()` instead.
*
* A class method call whose receiver is an `ActiveRecordModelClass`.
*/
deprecated class ActiveRecordModelClassMethodCall extends MethodCall {
ActiveRecordModelClassMethodCall() {
this = getAnUnknownActiveRecordModelClassCall().asCall().asExpr().getExpr()
}
/** Gets the `ActiveRecordModelClass` of the receiver of this method, if it can be determined. */
ActiveRecordModelClass getReceiverClass() {
this = result.getClassNode().trackModule().getMethod(_).asCall().asExpr().getExpr()
}
}
private predicate sqlFragmentArgumentInner(DataFlow::CallNode call, DataFlow::Node sink) {
call =
activeRecordQueryBuilderCall([
@@ -257,39 +196,6 @@ private predicate unsafeSqlExpr(Expr sqlFragmentExpr) {
sqlFragmentExpr instanceof MethodCall
}
/**
* DEPRECATED. Use the `SqlExecution` concept or `ActiveRecordSqlExecutionRange`.
*
* A method call that may result in executing unintended user-controlled SQL
* queries if the `getSqlFragmentSinkArgument()` expression is tainted by
* unsanitized user-controlled input. For example, supposing that `User` is an
* `ActiveRecord` model class, then
*
* ```rb
* User.where("name = '#{user_name}'")
* ```
*
* may be unsafe if `user_name` is from unsanitized user input, as a value such
* as `"') OR 1=1 --"` could result in the application looking up all users
* rather than just one with a matching name.
*/
deprecated class PotentiallyUnsafeSqlExecutingMethodCall extends ActiveRecordModelClassMethodCall {
private DataFlow::CallNode call;
PotentiallyUnsafeSqlExecutingMethodCall() {
call.asExpr().getExpr() = this and sqlFragmentArgument(call, _)
}
/**
* Gets the SQL fragment argument of this method call.
*/
Expr getSqlFragmentSinkArgument() {
exists(DataFlow::Node sink |
sqlFragmentArgument(call, sink) and result = sink.asExpr().getExpr()
)
}
}
/**
* A SQL execution arising from a call to the ActiveRecord library.
*/

View File

@@ -66,27 +66,6 @@ module ActiveResource {
}
}
/** DEPRECATED. Use `ModelClassNode` instead. */
deprecated class ModelClass extends ClassDeclaration {
private ModelClassNode cls;
ModelClass() { this = cls.getADeclaration() }
/** Gets the class for which this is a declaration. */
ModelClassNode getClassNode() { result = cls }
/** Gets the API node for this class object. */
deprecated API::Node getModelApiNode() { result = cls.trackModule() }
/** Gets a call to `site=`, which sets the base URL for this model. */
SiteAssignCall getASiteAssignment() { result = cls.getASiteAssignment() }
/** Holds if `c` sets a base URL which does not use HTTPS. */
predicate disablesCertificateValidation(SiteAssignCall c) {
cls.disablesCertificateValidation(c)
}
}
/**
* A call to a class method on an ActiveResource model class.
*
@@ -169,20 +148,6 @@ module ActiveResource {
CustomHttpCall() { this.getMethodName() = ["get", "post", "put", "patch", "delete"] }
}
/**
* DEPRECATED. Use `ModelClassNode.getAnInstanceReference()` instead.
*
* An ActiveResource model object.
*/
deprecated class ModelInstance extends DataFlow::Node {
private ModelClassNode cls;
ModelInstance() { this = cls.getAnInstanceReference().getAValueReachableFromSource() }
/** Gets the model class for this instance. */
ModelClassNode getModelClass() { result = cls }
}
/**
* A call to a method on an ActiveResource model object.
*/
@@ -191,22 +156,10 @@ module ActiveResource {
ModelInstanceMethodCall() { this = cls.getAnInstanceReference().getAMethodCall(_) }
/** Gets the model instance for this call. */
deprecated ModelInstance getInstance() { result = this.getReceiver() }
/** Gets the model class for this call. */
ModelClassNode getModelClass() { result = cls }
}
/**
* DEPRECATED. Use `CollectionSource` instead.
*
* A data flow node that may refer to a collection of ActiveResource model objects.
*/
deprecated class Collection extends DataFlow::Node {
Collection() { this = any(CollectionSource src).track().getAValueReachableFromSource() }
}
/**
* A call that returns a collection of ActiveResource model objects.
*/

View File

@@ -13,36 +13,6 @@ private import codeql.ruby.Concepts
* Provides classes for modeling the `Twirp` framework.
*/
module Twirp {
/**
* A Twirp service instantiation
*/
deprecated class ServiceInstantiation extends DataFlow::CallNode {
ServiceInstantiation() {
this = API::getTopLevelMember("Twirp").getMember("Service").getAnInstantiation()
}
/**
* Gets a handler's method.
*/
DataFlow::MethodNode getAHandlerMethodNode() {
result = this.getArgument(0).backtrack().getMethod(_).asCallable()
}
/**
* Gets a handler's method as an AST node.
*/
Ast::Method getAHandlerMethod() { result = this.getAHandlerMethodNode().asCallableAstNode() }
}
/**
* A Twirp client
*/
deprecated class ClientInstantiation extends DataFlow::CallNode {
ClientInstantiation() {
this = API::getTopLevelMember("Twirp").getMember("Client").getAnInstantiation()
}
}
/** The URL of a Twirp service, considered as a sink. */
class ServiceUrlAsSsrfSink extends ServerSideRequestForgery::Sink {
ServiceUrlAsSsrfSink() {

View File

@@ -34,9 +34,3 @@ private module InsecureDownloadConfig implements DataFlow::StateConfigSig {
* Taint-tracking for download of sensitive file through insecure connection.
*/
module InsecureDownloadFlow = DataFlow::GlobalWithState<InsecureDownloadConfig>;
/** DEPRECATED: Use `InsecureDownloadConfig` */
deprecated module Config = InsecureDownloadConfig;
/** DEPRECATED: Use `InsecureDownloadFlow` */
deprecated module Flow = InsecureDownloadFlow;

View File

@@ -7,15 +7,6 @@ private import codeql.ruby.DataFlow
private import codeql.ruby.TaintTracking
private import LdapInjectionCustomizations::LdapInjection as LI
/**
* Provides a taint-tracking configuration for detecting LDAP Injections vulnerabilities.
* DEPRECATED: Use `LdapInjectionFlow` instead
*/
deprecated module LdapInjection {
import LdapInjectionCustomizations::LdapInjection
import TaintTracking::Global<LdapInjectionConfig>
}
private module LdapInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof LI::Source }

View File

@@ -11,15 +11,6 @@ import codeql.ruby.AST
import codeql.ruby.DataFlow
import codeql.ruby.TaintTracking
/**
* Provides a taint-tracking configuration for cross-site scripting vulnerabilities.
* DEPRECATED: Use StoredXssFlow
*/
deprecated module StoredXss {
import XSS::StoredXss
import TaintTracking::Global<StoredXssConfig>
}
private module StoredXssConfig implements DataFlow::ConfigSig {
private import XSS::StoredXss

View File

@@ -43,8 +43,6 @@ module UnsafeCodeConstruction {
result = getANodeExecutedAsCode(TypeBackTracker::end(), codeExec)
}
deprecated import codeql.ruby.typetracking.TypeTracker as TypeTracker
/** Gets a node that is eventually executed as code at `codeExec`, type-tracked with `t`. */
private DataFlow::LocalSourceNode getANodeExecutedAsCode(
TypeBackTracker t, Concepts::CodeExecution codeExec

View File

@@ -48,8 +48,6 @@ module UnsafeShellCommandConstruction {
source = backtrackShellExec(TypeBackTracker::end(), shellExec)
}
deprecated import codeql.ruby.typetracking.TypeTracker as TypeTracker
private DataFlow::LocalSourceNode backtrackShellExec(
TypeBackTracker t, Concepts::SystemCommandExecution shellExec
) {

View File

@@ -10,14 +10,6 @@ private import codeql.ruby.DataFlow
private import codeql.ruby.TaintTracking
import XpathInjectionCustomizations::XpathInjection
/**
* Provides a taint-tracking configuration for detecting "Xpath Injection" vulnerabilities.
* DEPRECATED: Use `XpathInjectionFlow`
*/
deprecated module XpathInjection {
import TaintTracking::Global<XpathInjectionConfig>
}
private module XpathInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }

View File

@@ -8,929 +8,6 @@ private import TypeTrackerSpecific
private import codeql.util.Boolean
cached
private module Cached {
/**
* A description of a step on an inter-procedural data flow path.
*/
cached
deprecated newtype TStepSummary =
LevelStep() or
CallStep() or
ReturnStep() or
deprecated StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
deprecated LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
deprecated LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
basicLoadStoreStep(_, _, load, store)
} or
deprecated WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
deprecated WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
JumpStep()
cached
deprecated newtype TTypeTracker =
deprecated MkTypeTracker(Boolean hasCall, OptionalTypeTrackerContent content) {
content = noContent()
or
// Restrict `content` to those that might eventually match a load.
// We can't rely on `basicStoreStep` since `startInContent` might be used with
// a content that has no corresponding store.
exists(TypeTrackerContent loadContents |
(
basicLoadStep(_, _, loadContents)
or
basicLoadStoreStep(_, _, loadContents, _)
) and
compatibleContents(content, loadContents)
)
}
cached
deprecated newtype TTypeBackTracker =
deprecated MkTypeBackTracker(Boolean hasReturn, OptionalTypeTrackerContent content) {
content = noContent()
or
// As in MkTypeTracker, restrict `content` to those that might eventually match a store.
exists(TypeTrackerContent storeContent |
(
basicStoreStep(_, _, storeContent)
or
basicLoadStoreStep(_, _, _, storeContent)
) and
compatibleContents(storeContent, content)
)
}
/** Gets a type tracker with no content and the call bit set to the given value. */
cached
deprecated TypeTracker noContentTypeTracker(boolean hasCall) {
result = MkTypeTracker(hasCall, noContent())
}
/** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */
cached
deprecated TypeTracker append(TypeTracker tt, StepSummary step) {
exists(Boolean hasCall, OptionalTypeTrackerContent currentContents |
tt = MkTypeTracker(hasCall, currentContents)
|
step = LevelStep() and result = tt
or
step = CallStep() and result = MkTypeTracker(true, currentContents)
or
step = ReturnStep() and hasCall = false and result = tt
or
step = JumpStep() and
result = MkTypeTracker(false, currentContents)
or
exists(ContentFilter filter | result = tt |
step = WithContent(filter) and
currentContents = filter.getAMatchingContent()
or
step = WithoutContent(filter) and
not currentContents = filter.getAMatchingContent()
)
)
or
exists(TypeTrackerContent storeContents, boolean hasCall |
exists(TypeTrackerContent loadContents |
step = LoadStep(pragma[only_bind_into](loadContents)) and
tt = MkTypeTracker(hasCall, storeContents) and
compatibleContents(storeContents, loadContents) and
result = noContentTypeTracker(hasCall)
)
or
step = StoreStep(pragma[only_bind_into](storeContents)) and
tt = noContentTypeTracker(hasCall) and
result = MkTypeTracker(hasCall, storeContents)
)
or
exists(
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
boolean hasCall
|
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
compatibleContents(pragma[only_bind_into](currentContent), load) and
tt = MkTypeTracker(pragma[only_bind_into](hasCall), currentContent) and
result = MkTypeTracker(pragma[only_bind_out](hasCall), store)
)
}
pragma[nomagic]
deprecated private TypeBackTracker noContentTypeBackTracker(boolean hasReturn) {
result = MkTypeBackTracker(hasReturn, noContent())
}
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
cached
deprecated TypeBackTracker prepend(TypeBackTracker tbt, StepSummary step) {
exists(Boolean hasReturn, OptionalTypeTrackerContent content |
tbt = MkTypeBackTracker(hasReturn, content)
|
step = LevelStep() and result = tbt
or
step = CallStep() and hasReturn = false and result = tbt
or
step = ReturnStep() and result = MkTypeBackTracker(true, content)
or
step = JumpStep() and
result = MkTypeBackTracker(false, content)
or
exists(ContentFilter filter | result = tbt |
step = WithContent(filter) and
content = filter.getAMatchingContent()
or
step = WithoutContent(filter) and
not content = filter.getAMatchingContent()
)
)
or
exists(TypeTrackerContent loadContents, boolean hasReturn |
exists(TypeTrackerContent storeContents |
step = StoreStep(pragma[only_bind_into](storeContents)) and
tbt = MkTypeBackTracker(hasReturn, loadContents) and
compatibleContents(storeContents, loadContents) and
result = noContentTypeBackTracker(hasReturn)
)
or
step = LoadStep(pragma[only_bind_into](loadContents)) and
tbt = noContentTypeBackTracker(hasReturn) and
result = MkTypeBackTracker(hasReturn, loadContents)
)
or
exists(
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
boolean hasCall
|
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
compatibleContents(store, pragma[only_bind_into](currentContent)) and
tbt = MkTypeBackTracker(pragma[only_bind_into](hasCall), currentContent) and
result = MkTypeBackTracker(pragma[only_bind_out](hasCall), load)
)
}
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or intra-procedural step from `nodeFrom` to `nodeTo`.
*
* Steps contained in this predicate should _not_ depend on the call graph.
*/
cached
deprecated predicate stepNoCall(
TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary
) {
exists(Node mid | nodeFrom.flowsTo(mid) and smallstepNoCall(mid, nodeTo, summary))
}
/**
* Gets the summary that corresponds to having taken a forwards
* inter-procedural step from `nodeFrom` to `nodeTo`.
*/
cached
deprecated predicate stepCall(
TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary
) {
exists(Node mid | nodeFrom.flowsTo(mid) and smallstepCall(mid, nodeTo, summary))
}
cached
deprecated predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
jumpStep(nodeFrom, nodeTo) and
summary = JumpStep()
or
levelStepNoCall(nodeFrom, nodeTo) and
summary = LevelStep()
or
exists(TypeTrackerContent content |
flowsToStoreStep(nodeFrom, nodeTo, content) and
summary = StoreStep(content)
or
basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content)
)
or
exists(TypeTrackerContent loadContent, TypeTrackerContent storeContent |
flowsToLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) and
summary = LoadStoreStep(loadContent, storeContent)
)
or
exists(ContentFilter filter |
basicWithContentStep(nodeFrom, nodeTo, filter) and
summary = WithContent(filter)
or
basicWithoutContentStep(nodeFrom, nodeTo, filter) and
summary = WithoutContent(filter)
)
}
cached
deprecated predicate smallstepCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
callStep(nodeFrom, nodeTo) and summary = CallStep()
or
returnStep(nodeFrom, nodeTo) and
summary = ReturnStep()
or
levelStepCall(nodeFrom, nodeTo) and
summary = LevelStep()
}
}
private module Cached { }
private import Cached
deprecated private predicate step(
TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary
) {
stepNoCall(nodeFrom, nodeTo, summary)
or
stepCall(nodeFrom, nodeTo, summary)
}
pragma[nomagic]
deprecated private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
step(nodeFrom, _, summary)
}
deprecated private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
smallstepNoCall(nodeFrom, nodeTo, summary)
or
smallstepCall(nodeFrom, nodeTo, summary)
}
pragma[nomagic]
deprecated private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
smallstep(nodeFrom, _, summary)
}
/**
* Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`.
*
* Note that `nodeTo` will always be a local source node that flows to the place where the content
* is written in `basicStoreStep`. This may lead to the flow of information going "back in time"
* from the point of view of the execution of the program.
*
* For instance, if we interpret attribute writes in Python as writing to content with the same
* name as the attribute and consider the following snippet
*
* ```python
* def foo(y):
* x = Foo()
* bar(x)
* x.attr = y
* baz(x)
*
* def bar(x):
* z = x.attr
* ```
* for the attribute write `x.attr = y`, we will have `content` being the literal string `"attr"`,
* `nodeFrom` will be `y`, and `nodeTo` will be the object `Foo()` created on the first line of the
* function. This means we will track the fact that `x.attr` can have the type of `y` into the
* assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
*/
deprecated private predicate flowsToStoreStep(
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent content
) {
exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content))
}
/**
* Holds if `loadContent` is loaded from `nodeFrom` and written to `storeContent` of `nodeTo`.
*/
deprecated private predicate flowsToLoadStoreStep(
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent loadContent,
TypeTrackerContent storeContent
) {
exists(Node obj |
nodeTo.flowsTo(obj) and basicLoadStoreStep(nodeFrom, obj, loadContent, storeContent)
)
}
/**
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
*
* A description of a step on an inter-procedural data flow path.
*/
deprecated class StepSummary extends TStepSummary {
/** Gets a textual representation of this step summary. */
string toString() {
this instanceof LevelStep and result = "level"
or
this instanceof CallStep and result = "call"
or
this instanceof ReturnStep and result = "return"
or
exists(TypeTrackerContent content | this = StoreStep(content) | result = "store " + content)
or
exists(TypeTrackerContent content | this = LoadStep(content) | result = "load " + content)
or
exists(TypeTrackerContent load, TypeTrackerContent store |
this = LoadStoreStep(load, store) and
result = "load-store " + load + " -> " + store
)
or
this instanceof JumpStep and result = "jump"
}
}
/** Provides predicates for updating step summaries (`StepSummary`s). */
deprecated module StepSummary {
predicate append = Cached::append/2;
/**
* Gets the summary that corresponds to having taken a forwards
* inter-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate stepCall = Cached::stepCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* intra-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate stepNoCall = Cached::stepNoCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
stepNoCall(nodeFrom, nodeTo, summary)
or
stepCall(nodeFrom, nodeTo, summary)
}
/**
* Gets the summary that corresponds to having taken a forwards
* inter-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate smallstepNoCall = Cached::smallstepNoCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* intra-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate smallstepCall = Cached::smallstepCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*
* Unlike `StepSummary::step`, this predicate does not compress
* type-preserving steps.
*/
predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
smallstepNoCall(nodeFrom, nodeTo, summary)
or
smallstepCall(nodeFrom, nodeTo, summary)
}
/** Gets the step summary for a level step. */
StepSummary levelStep() { result = LevelStep() }
/** Gets the step summary for a call step. */
StepSummary callStep() { result = CallStep() }
/** Gets the step summary for a return step. */
StepSummary returnStep() { result = ReturnStep() }
/** Gets the step summary for storing into `content`. */
StepSummary storeStep(TypeTrackerContent content) { result = StoreStep(content) }
/** Gets the step summary for loading from `content`. */
StepSummary loadStep(TypeTrackerContent content) { result = LoadStep(content) }
/** Gets the step summary for loading from `load` and then storing into `store`. */
StepSummary loadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
result = LoadStoreStep(load, store)
}
/** Gets the step summary for a step that only permits contents matched by `filter`. */
StepSummary withContent(ContentFilter filter) { result = WithContent(filter) }
/** Gets the step summary for a step that blocks contents matched by `filter`. */
StepSummary withoutContent(ContentFilter filter) { result = WithoutContent(filter) }
/** Gets the step summary for a jump step. */
StepSummary jumpStep() { result = JumpStep() }
}
/**
* DEPRECATED: Use `codeql.ruby.typetracking.TypeTracking` instead.
*
* 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
* DataFlow::TypeTrackingNode myType(DataFlow::TypeTracker t) {
* t.start() and
* result = < source of myType >
* or
* exists (DataFlow::TypeTracker t2 |
* result = myType(t2).track(t2, t)
* )
* }
*
* DataFlow::Node myType() { myType(DataFlow::TypeTracker::end()).flowsTo(result) }
* ```
*
* Instead of `result = myType(t2).track(t2, t)`, you can also use the equivalent
* `t = t2.step(myType(t2), result)`. If you additionally want to track individual
* intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`.
*/
deprecated class TypeTracker extends TTypeTracker {
Boolean hasCall;
OptionalTypeTrackerContent content;
TypeTracker() { this = MkTypeTracker(hasCall, content) }
/** Gets the summary resulting from appending `step` to this type-tracking summary. */
TypeTracker append(StepSummary step) { result = append(this, step) }
/** Gets a textual representation of this summary. */
string toString() {
exists(string withCall, string withContent |
(if hasCall = true then withCall = "with" else withCall = "without") and
(
if content != noContent()
then withContent = " with content " + content
else withContent = ""
) and
result = "type tracker " + withCall + " call steps" + withContent
)
}
/**
* Holds if this is the starting point of type tracking.
*/
predicate start() { hasCall = false and content = noContent() }
/**
* Holds if this is the starting point of type tracking, and the value starts in the content named `contentName`.
* The type tracking only ends after the content has been loaded.
*/
predicate startInContent(TypeTrackerContent contentName) {
hasCall = false and content = contentName
}
/**
* Holds if this is the starting point of type tracking
* when tracking a parameter into a call, but not out of it.
*/
predicate call() { hasCall = true and content = noContent() }
/**
* Holds if this is the end point of type tracking.
*/
predicate end() { content = noContent() }
/**
* INTERNAL. DO NOT USE.
*
* Holds if this type has been tracked into a call.
*/
boolean hasCall() { result = hasCall }
/**
* INTERNAL. DO NOT USE.
*
* Gets the content associated with this type tracker.
*/
OptionalTypeTrackerContent getContent() { result = content }
/**
* Gets a type tracker that starts where this one has left off to allow continued
* tracking.
*
* This predicate is only defined if the type is not associated to a piece of content.
*/
TypeTracker continue() { content = noContent() and result = this }
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
bindingset[nodeFrom, this]
pragma[inline_late]
pragma[noopt]
TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
exists(StepSummary summary |
stepProj(nodeFrom, summary) and
result = this.append(summary) and
step(nodeFrom, nodeTo, summary)
)
}
bindingset[nodeFrom, this]
pragma[inline_late]
pragma[noopt]
private TypeTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
smallstepProj(nodeFrom, summary) and
result = this.append(summary) and
smallstep(nodeFrom, nodeTo, summary)
)
}
/**
* Gets the summary that corresponds to having taken a forwards
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*
* Unlike `TypeTracker::step`, this predicate exposes all edges
* in the flow graph, and not just the edges between `Node`s.
* It may therefore be less performant.
*
* Type tracking predicates using small steps typically take the following form:
* ```ql
* DataFlow::Node myType(DataFlow::TypeTracker t) {
* t.start() and
* result = < source of myType >
* or
* exists (DataFlow::TypeTracker t2 |
* t = t2.smallstep(myType(t2), result)
* )
* }
*
* DataFlow::Node myType() {
* result = myType(DataFlow::TypeTracker::end())
* }
* ```
*/
pragma[inline]
TypeTracker smallstep(Node nodeFrom, Node nodeTo) {
result = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
result = this
}
}
/** Provides predicates for implementing custom `TypeTracker`s. */
deprecated module TypeTracker {
/**
* Gets a valid end point of type tracking.
*/
TypeTracker end() { result.end() }
/**
* INTERNAL USE ONLY.
*
* Gets a valid end point of type tracking with the call bit set to the given value.
*/
predicate end = Cached::noContentTypeTracker/1;
}
pragma[nomagic]
deprecated private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
step(_, nodeTo, summary)
}
deprecated private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
smallstep(_, nodeTo, summary)
}
/**
* DEPRECATED: Use `codeql.ruby.typetracking.TypeTracking` instead.
*
* A summary of the steps needed to back-track a use of a value to a given dataflow node.
*
* This can for example be used to track callbacks that are passed to a certain API,
* so we can model specific parameters of that callback as having a certain type.
*
* Note that type back-tracking does not provide a source/sink relation, that is,
* it may determine that a node will be used in an API call somewhere, but it won't
* determine exactly where that use was, or the path that led to the use.
*
* It is recommended that all uses of this type are written in the following form,
* for back-tracking some callback type `myCallback`:
*
* ```ql
* DataFlow::TypeTrackingNode myCallback(DataFlow::TypeBackTracker t) {
* t.start() and
* result = (< some API call >).getArgument(< n >).getALocalSource()
* or
* exists (DataFlow::TypeBackTracker t2 |
* result = myCallback(t2).backtrack(t2, t)
* )
* }
*
* DataFlow::TypeTrackingNode myCallback() { result = myCallback(DataFlow::TypeBackTracker::end()) }
* ```
*
* Instead of `result = myCallback(t2).backtrack(t2, t)`, you can also use the equivalent
* `t2 = t.step(result, myCallback(t2))`. If you additionally want to track individual
* intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`.
*/
deprecated class TypeBackTracker extends TTypeBackTracker {
Boolean hasReturn;
OptionalTypeTrackerContent content;
TypeBackTracker() { this = MkTypeBackTracker(hasReturn, content) }
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
TypeBackTracker prepend(StepSummary step) { result = prepend(this, step) }
/** Gets a textual representation of this summary. */
string toString() {
exists(string withReturn, string withContent |
(if hasReturn = true then withReturn = "with" else withReturn = "without") and
(
if content != noContent()
then withContent = " with content " + content
else withContent = ""
) and
result = "type back-tracker " + withReturn + " return steps" + withContent
)
}
/**
* Holds if this is the starting point of type tracking.
*/
predicate start() { hasReturn = false and content = noContent() }
/**
* Holds if this is the end point of type tracking.
*/
predicate end() { content = noContent() }
/**
* INTERNAL. DO NOT USE.
*
* Holds if this type has been back-tracked into a call through return edge.
*/
boolean hasReturn() { result = hasReturn }
/**
* Gets a type tracker that starts where this one has left off to allow continued
* tracking.
*
* This predicate is only defined if the type has not been tracked into a piece of content.
*/
TypeBackTracker continue() { content = noContent() and result = this }
/**
* Gets the summary that corresponds to having taken a backwards
* heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
*/
bindingset[nodeTo, result]
pragma[inline_late]
pragma[noopt]
TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
exists(StepSummary summary |
backStepProj(nodeTo, summary) and
this = result.prepend(summary) and
step(nodeFrom, nodeTo, summary)
)
}
bindingset[nodeTo, result]
pragma[inline_late]
pragma[noopt]
private TypeBackTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
backSmallstepProj(nodeTo, summary) and
this = result.prepend(summary) and
smallstep(nodeFrom, nodeTo, summary)
)
}
/**
* Gets the summary that corresponds to having taken a backwards
* local, heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
*
* Unlike `TypeBackTracker::step`, this predicate exposes all edges
* in the flowgraph, and not just the edges between
* `TypeTrackingNode`s. It may therefore be less performant.
*
* Type tracking predicates using small steps typically take the following form:
* ```ql
* DataFlow::Node myType(DataFlow::TypeBackTracker t) {
* t.start() and
* result = < some API call >.getArgument(< n >)
* or
* exists (DataFlow::TypeBackTracker t2 |
* t = t2.smallstep(result, myType(t2))
* )
* }
*
* DataFlow::Node myType() {
* result = myType(DataFlow::TypeBackTracker::end())
* }
* ```
*/
pragma[inline]
TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) {
this = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
this = result
}
/**
* Gets a forwards summary that is compatible with this backwards summary.
* That is, if this summary describes the steps needed to back-track a value
* from `sink` to `mid`, and the result is a valid summary of the steps needed
* to track a value from `source` to `mid`, then the value from `source` may
* also flow to `sink`.
*/
TypeTracker getACompatibleTypeTracker() {
exists(boolean hasCall, OptionalTypeTrackerContent c |
result = MkTypeTracker(hasCall, c) and
(
compatibleContents(c, content)
or
content = noContent() and c = content
)
|
hasCall = false
or
this.hasReturn() = false
)
}
}
/** Provides predicates for implementing custom `TypeBackTracker`s. */
deprecated module TypeBackTracker {
/**
* Gets a valid end point of type back-tracking.
*/
TypeBackTracker end() { result.end() }
}
/**
* INTERNAL: Do not use.
*
* Provides logic for constructing a call graph in mutual recursion with type tracking.
*
* When type tracking is used to construct a call graph, we cannot use the join-order
* from `stepInlineLate`, because `step` becomes a recursive call, which means that we
* will have a conjunct with 3 recursive calls: the call to `step`, the call to `stepProj`,
* and the recursive type tracking call itself. The solution is to split the three-way
* non-linear recursion into two non-linear predicates: one that first joins with the
* projected `stepCall` relation, followed by a predicate that joins with the full
* `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the
* same way as in `stepInlineLate`).
*/
deprecated module CallGraphConstruction {
/** The input to call graph construction. */
signature module InputSig {
/** A state to track during type tracking. */
class State;
/** Holds if type tracking should start at `start` in state `state`. */
deprecated predicate start(Node start, State state);
/**
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
* which _does not_ depend on the call graph.
*
* Implementing this predicate using `StepSummary::[small]stepNoCall` yields
* standard type tracking.
*/
deprecated predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary);
/**
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
* which _does_ depend on the call graph.
*
* Implementing this predicate using `StepSummary::[small]stepCall` yields
* standard type tracking.
*/
deprecated predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary);
/** A projection of an element from the state space. */
class StateProj;
/** Gets the projection of `state`. */
StateProj stateProj(State state);
/** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */
deprecated predicate filter(Node n, StateProj stateProj);
}
/** Provides the `track` predicate for use in call graph construction. */
module Make<InputSig Input> {
pragma[nomagic]
deprecated private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
Input::stepNoCall(nodeFrom, _, summary)
}
pragma[nomagic]
deprecated private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
Input::stepCall(nodeFrom, _, summary)
}
bindingset[nodeFrom, t]
pragma[inline_late]
pragma[noopt]
deprecated private TypeTracker stepNoCallInlineLate(
TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
) {
exists(StepSummary summary |
stepNoCallProj(nodeFrom, summary) and
result = t.append(summary) and
Input::stepNoCall(nodeFrom, nodeTo, summary)
)
}
bindingset[state]
pragma[inline_late]
private Input::StateProj stateProjInlineLate(Input::State state) {
result = Input::stateProj(state)
}
pragma[nomagic]
deprecated private Node track(Input::State state, TypeTracker t) {
t.start() and Input::start(result, state)
or
exists(Input::StateProj stateProj |
stateProj = stateProjInlineLate(state) and
not Input::filter(result, stateProj)
|
exists(TypeTracker t2 | t = stepNoCallInlineLate(t2, track(state, t2), result))
or
exists(StepSummary summary |
// non-linear recursion
Input::stepCall(trackCall(state, t, summary), result, summary)
)
)
}
bindingset[t, summary]
pragma[inline_late]
deprecated private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
result = t.append(summary)
}
pragma[nomagic]
deprecated private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) {
exists(TypeTracker t2 |
// non-linear recursion
result = track(state, t2) and
stepCallProj(result, summary) and
t = appendInlineLate(t2, summary)
)
}
/** Gets a node that can be reached from _some_ start node in state `state`. */
pragma[nomagic]
deprecated Node track(Input::State state) { result = track(state, TypeTracker::end()) }
}
/** A simple version of `CallGraphConstruction` that uses standard type tracking. */
module Simple {
/** The input to call graph construction. */
signature module InputSig {
/** A state to track during type tracking. */
class State;
/** Holds if type tracking should start at `start` in state `state`. */
deprecated predicate start(Node start, State state);
/** Holds if type tracking should stop at `n`. */
deprecated predicate filter(Node n);
}
/** Provides the `track` predicate for use in call graph construction. */
module Make<InputSig Input> {
deprecated private module I implements CallGraphConstruction::InputSig {
private import codeql.util.Unit
class State = Input::State;
predicate start(Node start, State state) { Input::start(start, state) }
predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary) {
StepSummary::stepNoCall(nodeFrom, nodeTo, summary)
}
predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary) {
StepSummary::stepCall(nodeFrom, nodeTo, summary)
}
class StateProj = Unit;
Unit stateProj(State state) { exists(state) and exists(result) }
predicate filter(Node n, Unit u) {
Input::filter(n) and
exists(u)
}
}
deprecated import CallGraphConstruction::Make<I>
}
}
}

View File

@@ -2,134 +2,3 @@ private import codeql.ruby.dataflow.internal.DataFlowPublic as DataFlowPublic
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import internal.TypeTrackingImpl as TypeTrackingImpl
deprecated import codeql.util.Boolean
deprecated class Node = DataFlowPublic::Node;
deprecated class TypeTrackingNode = DataFlowPublic::LocalSourceNode;
deprecated class TypeTrackerContent = DataFlowPublic::ContentSet;
/**
* An optional content set, that is, a `ContentSet` or the special "no content set" value.
*/
deprecated class OptionalTypeTrackerContent extends DataFlowPrivate::TOptionalContentSet {
/** Gets a textual representation of this content set. */
string toString() {
this instanceof DataFlowPrivate::TNoContentSet and
result = "no content"
or
result = this.(DataFlowPublic::ContentSet).toString()
}
}
/**
* A label to use for `WithContent` and `WithoutContent` steps, restricting
* which `ContentSet` may pass through.
*/
deprecated class ContentFilter = TypeTrackingImpl::TypeTrackingInput::ContentFilter;
/** Module for getting `ContentFilter` values. */
deprecated module ContentFilter {
/** Gets the filter that only allow element contents. */
ContentFilter hasElements() { any() }
}
/**
* Holds if a value stored with `storeContents` can be read back with `loadContents`.
*/
pragma[inline]
deprecated predicate compatibleContents(
TypeTrackerContent storeContents, TypeTrackerContent loadContents
) {
storeContents.getAStoreContent() = loadContents.getAReadContent()
}
/** Gets the "no content set" value to use for a type tracker not inside any content. */
deprecated OptionalTypeTrackerContent noContent() { result = DataFlowPrivate::TNoContentSet() }
/** Holds if there is a simple local flow step from `nodeFrom` to `nodeTo` */
deprecated predicate simpleLocalFlowStep =
TypeTrackingImpl::TypeTrackingInput::simpleLocalSmallStep/2;
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
deprecated predicate jumpStep = TypeTrackingImpl::TypeTrackingInput::jumpStep/2;
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
deprecated predicate levelStepCall = TypeTrackingImpl::TypeTrackingInput::levelStepCall/2;
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
deprecated predicate levelStepNoCall = TypeTrackingImpl::TypeTrackingInput::levelStepNoCall/2;
/**
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
*
* Flow into summarized library methods is not included, as that will lead to negative
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
deprecated predicate callStep = TypeTrackingImpl::TypeTrackingInput::callStep/2;
/**
* Holds if `nodeFrom` steps to `nodeTo` by being returned from a call.
*
* Flow out of summarized library methods is not included, as that will lead to negative
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
deprecated predicate returnStep = TypeTrackingImpl::TypeTrackingInput::returnStep/2;
/**
* Holds if `nodeFrom` is being written to the `contents` of the object
* in `nodeTo`.
*
* Note that the choice of `nodeTo` does not have to make sense
* "chronologically". All we care about is whether the `contents` of
* `nodeTo` can have a specific type, and the assumption is that if a specific
* type appears here, then any access of that particular content can yield
* something of that particular type.
*
* Thus, in an example such as
*
* ```rb
* def foo(y)
* x = Foo.new
* bar(x)
* x.content = y
* baz(x)
* end
*
* def bar(x)
* z = x.content
* end
* ```
* for the content write `x.content = y`, we will have `contents` being the
* literal string `"content"`, `nodeFrom` will be `y`, and `nodeTo` will be the
* `Foo` object created on the first line of the function. This means we will
* track the fact that `x.content` can have the type of `y` into the assignment
* to `z` inside `bar`, even though this content write happens _after_ `bar` is
* called.
*/
deprecated predicate basicStoreStep = TypeTrackingImpl::TypeTrackingInput::storeStep/3;
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
deprecated predicate basicLoadStep = TypeTrackingImpl::TypeTrackingInput::loadStep/3;
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
deprecated predicate basicLoadStoreStep = TypeTrackingImpl::TypeTrackingInput::loadStoreStep/4;
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
*/
deprecated predicate basicWithoutContentStep =
TypeTrackingImpl::TypeTrackingInput::withoutContentStep/3;
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
*/
deprecated predicate basicWithContentStep = TypeTrackingImpl::TypeTrackingInput::withContentStep/3;