mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge branch 'main' into expand-ruby-ssrf-sinks-faraday-connection-new
This commit is contained in:
@@ -3,7 +3,7 @@ description: Builds the Ruby CodeQL pack
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
||||
@@ -216,7 +216,7 @@ struct Visitor<'a> {
|
||||
schema: &'a NodeTypeMap,
|
||||
/// A stack for gathering information from child nodes. Whenever a node is
|
||||
/// entered the parent's [Label], child counter, and an empty list is pushed.
|
||||
/// All children append their data to the the list. When the visitor leaves a
|
||||
/// All children append their data to the list. When the visitor leaves a
|
||||
/// node the list containing the child data is popped from the stack and
|
||||
/// matched against the dbscheme for the node. If the expectations are met
|
||||
/// the corresponding row definitions are added to the trap_output.
|
||||
|
||||
@@ -68,7 +68,6 @@ fn main() -> std::io::Result<()> {
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("ruby_extractor=warn")),
|
||||
)
|
||||
.init();
|
||||
tracing::warn!("Support for Ruby is currently in Beta: https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/");
|
||||
let num_threads = num_codeql_threads();
|
||||
tracing::info!(
|
||||
"Using {} {}",
|
||||
|
||||
@@ -43,7 +43,7 @@ pub enum FieldTypeInfo {
|
||||
},
|
||||
|
||||
/// The field can be one of several tokens, so the db type will be an `int`
|
||||
/// with a `case @foo.kind` for each possiblity.
|
||||
/// with a `case @foo.kind` for each possibility.
|
||||
ReservedWordInt(BTreeMap<String, (usize, String)>),
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `ActiveJob::Serializers.deserialize` is considered to be a code execution sink.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* More sources of remote input arising from methods on `ActionDispatch::Request`
|
||||
are now recognised.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The response value returned by the `Faraday#run_request` method is now also considered a source of remote input.
|
||||
4
ruby/ql/lib/change-notes/2022-10-14-digest-model.md
Normal file
4
ruby/ql/lib/change-notes/2022-10-14-digest-model.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The hashing algorithms from `Digest` and `OpenSSL::Digest` are now recognized and can be flagged by the `rb/weak-cryptographic-algorithm` query.
|
||||
@@ -203,7 +203,7 @@ module API {
|
||||
/**
|
||||
* Gets a node representing a call to `method` on the receiver represented by this node.
|
||||
*/
|
||||
Node getMethod(string method) {
|
||||
MethodAccessNode getMethod(string method) {
|
||||
result = this.getASubclass().getASuccessor(Label::method(method))
|
||||
}
|
||||
|
||||
@@ -898,7 +898,7 @@ module API {
|
||||
/** Gets the `subclass` edge label. */
|
||||
LabelSubclass subclass() { any() }
|
||||
|
||||
/** Gets the label representing the given keword argument/parameter. */
|
||||
/** 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. */
|
||||
|
||||
@@ -250,6 +250,11 @@ module Http {
|
||||
|
||||
/** Gets a string that identifies the framework used for this route setup. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Gets the HTTP method name, in lowercase, that this handler will respond to.
|
||||
*/
|
||||
string getHttpMethod() { result = super.getHttpMethod() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP routing APIs. */
|
||||
@@ -287,9 +292,34 @@ module Http {
|
||||
|
||||
/** Gets a string that identifies the framework used for this route setup. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Gets the HTTP method name, in all caps, that this handler will respond to.
|
||||
*/
|
||||
abstract string getHttpMethod();
|
||||
}
|
||||
}
|
||||
|
||||
/** A kind of request input. */
|
||||
class RequestInputKind extends string {
|
||||
RequestInputKind() { this = ["parameter", "header", "body", "url", "cookie"] }
|
||||
}
|
||||
|
||||
/** Input from the parameters of a request. */
|
||||
RequestInputKind parameterInputKind() { result = "parameter" }
|
||||
|
||||
/** Input from the headers of a request. */
|
||||
RequestInputKind headerInputKind() { result = "header" }
|
||||
|
||||
/** Input from the body of a request. */
|
||||
RequestInputKind bodyInputKind() { result = "body" }
|
||||
|
||||
/** Input from the URL of a request. */
|
||||
RequestInputKind urlInputKind() { result = "url" }
|
||||
|
||||
/** Input from the cookies of a request. */
|
||||
RequestInputKind cookieInputKind() { result = "cookie" }
|
||||
|
||||
/**
|
||||
* An access to a user-controlled HTTP request input. For example, the URL or body of a request.
|
||||
* Instances of this class automatically become `RemoteFlowSource`s.
|
||||
@@ -304,6 +334,32 @@ module Http {
|
||||
* This is typically the name of the method that gives rise to this input.
|
||||
*/
|
||||
string getSourceType() { result = super.getSourceType() }
|
||||
|
||||
/**
|
||||
* Gets the kind of the accessed input,
|
||||
* Can be one of "parameter", "header", "body", "url", "cookie".
|
||||
*/
|
||||
RequestInputKind getKind() { result = super.getKind() }
|
||||
|
||||
/**
|
||||
* Holds if this part of the request may be controlled by a third party,
|
||||
* that is, an agent other than the one who sent the request.
|
||||
*
|
||||
* This is true for the URL, query parameters, and request body.
|
||||
* These can be controlled by a malicious third party in the following scenarios:
|
||||
*
|
||||
* - The user clicks a malicious link or is otherwise redirected to a malicious URL.
|
||||
* - The user visits a web site that initiates a form submission or AJAX request on their behalf.
|
||||
*
|
||||
* In these cases, the request is technically sent from the user's browser, but
|
||||
* the user is not in direct control of the URL or POST body.
|
||||
*
|
||||
* Headers are never considered third-party controllable by this predicate, although the
|
||||
* third party does have some control over the the Referer and Origin headers.
|
||||
*/
|
||||
predicate isThirdPartyControllable() {
|
||||
this.getKind() = [parameterInputKind(), urlInputKind(), bodyInputKind()]
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP request inputs. */
|
||||
@@ -321,6 +377,12 @@ module Http {
|
||||
* This is typically the name of the method that gives rise to this input.
|
||||
*/
|
||||
abstract string getSourceType();
|
||||
|
||||
/**
|
||||
* Gets the kind of the accessed input,
|
||||
* Can be one of "parameter", "header", "body", "url", "cookie".
|
||||
*/
|
||||
abstract RequestInputKind getKind();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +405,12 @@ module Http {
|
||||
|
||||
/** Gets a string that identifies the framework used for this route setup. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Gets an HTTP method name, in all caps, that this handler will respond to.
|
||||
* Handlers can potentially respond to multiple HTTP methods.
|
||||
*/
|
||||
string getAnHttpMethod() { result = super.getAnHttpMethod() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP request handlers. */
|
||||
@@ -364,6 +432,12 @@ module Http {
|
||||
|
||||
/** Gets a string that identifies the framework used for this request handler. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Gets an HTTP method name, in all caps, that this handler will respond to.
|
||||
* Handlers can potentially respond to multiple HTTP methods.
|
||||
*/
|
||||
abstract string getAnHttpMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,6 +452,8 @@ module Http {
|
||||
}
|
||||
|
||||
override string getFramework() { result = rs.getFramework() }
|
||||
|
||||
override string getAnHttpMethod() { result = rs.getHttpMethod() }
|
||||
}
|
||||
|
||||
/** A parameter that will receive parts of the url when handling an incoming request. */
|
||||
@@ -387,6 +463,39 @@ module Http {
|
||||
RoutedParameter() { this.getParameter() = handler.getARoutedParameter() }
|
||||
|
||||
override string getSourceType() { result = handler.getFramework() + " RoutedParameter" }
|
||||
|
||||
override RequestInputKind getKind() { result = parameterInputKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that writes data to a header in an HTTP response.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `HeaderWriteAccess::Range` instead.
|
||||
*/
|
||||
class HeaderWriteAccess extends DataFlow::Node instanceof HeaderWriteAccess::Range {
|
||||
/** Gets the (lower case) name of the header that is written to. */
|
||||
string getName() { result = super.getName().toLowerCase() }
|
||||
|
||||
/** Gets the value that is written to the header. */
|
||||
DataFlow::Node getValue() { result = super.getValue() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP header writes. */
|
||||
module HeaderWriteAccess {
|
||||
/**
|
||||
* A data flow node that writes data to the header in an HTTP response.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `HeaderWriteAccess` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the name of the header that is written to. */
|
||||
abstract string getName();
|
||||
|
||||
/** Gets the value that is written to the header. */
|
||||
abstract DataFlow::Node getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
private import codeql.ruby.frameworks.Core
|
||||
private import codeql.ruby.frameworks.ActionCable
|
||||
private import codeql.ruby.frameworks.ActionController
|
||||
private import codeql.ruby.frameworks.ActiveJob
|
||||
private import codeql.ruby.frameworks.ActionMailer
|
||||
private import codeql.ruby.frameworks.ActiveRecord
|
||||
private import codeql.ruby.frameworks.ActiveResource
|
||||
|
||||
@@ -106,7 +106,7 @@ class MethodCall extends Call instanceof MethodCallImpl {
|
||||
final Block getBlock() { result = super.getBlockImpl() }
|
||||
|
||||
/**
|
||||
* Holds if the safe nagivation operator (`&.`) is used in this call.
|
||||
* Holds if the safe navigation operator (`&.`) is used in this call.
|
||||
* ```rb
|
||||
* foo&.empty?
|
||||
* ```
|
||||
|
||||
@@ -65,7 +65,7 @@ class ConstantValue extends TConstantValue {
|
||||
/** Holds if this is the string value `s`. */
|
||||
predicate isString(string s) { s = this.getString() }
|
||||
|
||||
/** Gets the symbol value (exluding the `:` prefix), if this is a symbol. */
|
||||
/** Gets the symbol value (excluding the `:` prefix), if this is a symbol. */
|
||||
string getSymbol() { this = TSymbol(result) }
|
||||
|
||||
/** Holds if this is the symbol value `:s`. */
|
||||
|
||||
@@ -138,9 +138,26 @@ private module Cached {
|
||||
cached
|
||||
string resolveConstantWrite(ConstantWriteAccess c) { result = resolveConstantWriteAccess(c) }
|
||||
|
||||
/**
|
||||
* Gets a method named `name` that is available in module `m`. This includes methods
|
||||
* that are included/prepended into `m` and methods available on base classes of `m`.
|
||||
*/
|
||||
cached
|
||||
Method lookupMethod(Module m, string name) { TMethod(result) = lookupMethodOrConst(m, name) }
|
||||
|
||||
/**
|
||||
* Gets a method named `name` that is available in a sub class of module `m`. This
|
||||
* includes methods that are included/prepended into any of the sub classes of `m`,
|
||||
* but not methods inherited from base classes.
|
||||
*/
|
||||
cached
|
||||
Method lookupMethodInSubClasses(Module m, string name) {
|
||||
exists(Module sub | sub.getSuperClass() = m |
|
||||
TMethod(result) = lookupMethodOrConst0(sub, name) or
|
||||
result = lookupMethodInSubClasses(sub, name)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Expr lookupConst(Module m, string name) {
|
||||
TExpr(result) = lookupMethodOrConst(m, name)
|
||||
@@ -394,7 +411,7 @@ private module ResolveImpl {
|
||||
|
||||
/**
|
||||
* The qualified names of the ancestors of a class/module. The ancestors should be an ordered list
|
||||
* of the ancestores of `prepend`ed modules, the module itself , the ancestors or `include`d modules
|
||||
* of the ancestors of `prepend`ed modules, the module itself , the ancestors or `include`d modules
|
||||
* and the ancestors of the super class. The priority value only distinguishes the kind of ancestor,
|
||||
* it does not order the ancestors within a group of the same kind. This is an over-approximation, however,
|
||||
* computing the precise order is tricky because it depends on the evaluation/file loading order.
|
||||
|
||||
@@ -676,7 +676,9 @@ private class SelfVariableAccessReal extends SelfVariableAccessImpl, TSelfReal {
|
||||
private SelfVariable var;
|
||||
|
||||
SelfVariableAccessReal() {
|
||||
exists(Ruby::Self self | this = TSelfReal(self) and var = TSelfVariable(scopeOf(self)))
|
||||
exists(Ruby::Self self |
|
||||
this = TSelfReal(self) and var = TSelfVariable(scopeOf(self).getEnclosingSelfScope())
|
||||
)
|
||||
}
|
||||
|
||||
final override SelfVariable getVariableImpl() { result = var }
|
||||
|
||||
@@ -687,6 +687,15 @@ module ExprNodes {
|
||||
final ExprCfgNode getValue() { e.hasCfgChild(e.getValue(), this, result) }
|
||||
}
|
||||
|
||||
/** A control-flow node that wraps a `VariableAccess` AST expression. */
|
||||
class VariableAccessCfgNode extends ExprCfgNode {
|
||||
override string getAPrimaryQlClass() { result = "VariableAccessCfgNode" }
|
||||
|
||||
override VariableAccess e;
|
||||
|
||||
final override VariableAccess getExpr() { result = ExprCfgNode.super.getExpr() }
|
||||
}
|
||||
|
||||
/** A control-flow node that wraps a `VariableReadAccess` AST expression. */
|
||||
class VariableReadAccessCfgNode extends ExprCfgNode {
|
||||
override string getAPrimaryQlClass() { result = "VariableReadAccessCfgNode" }
|
||||
|
||||
@@ -885,7 +885,7 @@ module TestOutput {
|
||||
/**
|
||||
* Gets a string used to resolve ties in node and edge ordering.
|
||||
*/
|
||||
string getOrderDisambuigation() { result = "" }
|
||||
string getOrderDisambiguation() { result = "" }
|
||||
}
|
||||
|
||||
query predicate nodes(RelevantNode n, string attr, string val) {
|
||||
@@ -900,7 +900,7 @@ module TestOutput {
|
||||
order by
|
||||
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
|
||||
l.getStartColumn(), l.getEndLine(), l.getEndColumn(), p.toString(),
|
||||
p.getOrderDisambuigation()
|
||||
p.getOrderDisambiguation()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
@@ -923,7 +923,7 @@ module TestOutput {
|
||||
order by
|
||||
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
|
||||
l.getStartColumn(), l.getEndLine(), l.getEndColumn(), t.toString(), s.toString(),
|
||||
s.getOrderDisambuigation()
|
||||
s.getOrderDisambiguation()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ module SummaryComponent {
|
||||
|
||||
/**
|
||||
* Gets a summary component that represents an element in a collection at a specific
|
||||
* known index `cv`, or an uknown index.
|
||||
* known index `cv`, or an unknown index.
|
||||
*/
|
||||
SummaryComponent elementKnownOrUnknown(ConstantValue cv) {
|
||||
result = SC::content(TKnownOrUnknownElementContent(TKnownElementContent(cv)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Provides an extension point for for modeling user-controlled data.
|
||||
* Provides an extension point for modeling user-controlled data.
|
||||
* Such data is often used as data-flow sources in security queries.
|
||||
*/
|
||||
|
||||
|
||||
@@ -151,17 +151,24 @@ private class NormalCall extends DataFlowCall, TNormalCall {
|
||||
override Location getLocation() { result = c.getLocation() }
|
||||
}
|
||||
|
||||
/** A call for which we want to compute call targets. */
|
||||
private class RelevantCall extends CfgNodes::ExprNodes::CallCfgNode {
|
||||
pragma[nomagic]
|
||||
RelevantCall() {
|
||||
// Temporarily disable operation resolution (due to bad performance)
|
||||
not this.getExpr() instanceof Operation
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate methodCall(
|
||||
CfgNodes::ExprNodes::CallCfgNode call, DataFlow::Node receiver, string method
|
||||
) {
|
||||
private predicate methodCall(RelevantCall call, DataFlow::Node receiver, string method) {
|
||||
method = call.getExpr().(MethodCall).getMethodName() and
|
||||
receiver.asExpr() = call.getReceiver()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowsToMethodCall(
|
||||
CfgNodes::ExprNodes::CallCfgNode call, DataFlow::LocalSourceNode sourceNode, string method
|
||||
private predicate flowsToMethodCallReceiver(
|
||||
RelevantCall call, DataFlow::LocalSourceNode sourceNode, string method
|
||||
) {
|
||||
exists(DataFlow::Node receiver |
|
||||
methodCall(call, receiver, method) and
|
||||
@@ -169,7 +176,12 @@ private predicate flowsToMethodCall(
|
||||
)
|
||||
}
|
||||
|
||||
private Block yieldCall(CfgNodes::ExprNodes::CallCfgNode call) {
|
||||
pragma[nomagic]
|
||||
private predicate moduleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
|
||||
flowsToMethodCallReceiver(call, trackModuleAccess(m), method)
|
||||
}
|
||||
|
||||
private Block yieldCall(RelevantCall call) {
|
||||
call.getExpr() instanceof YieldCall and
|
||||
exists(BlockParameterNode node |
|
||||
node = trackBlock(result) and
|
||||
@@ -178,7 +190,7 @@ private Block yieldCall(CfgNodes::ExprNodes::CallCfgNode call) {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate superCall(CfgNodes::ExprNodes::CallCfgNode call, Module superClass, string method) {
|
||||
private predicate superCall(RelevantCall call, Module superClass, string method) {
|
||||
call.getExpr() instanceof SuperCall and
|
||||
exists(Module tp |
|
||||
tp = call.getExpr().getEnclosingModule().getModule() and
|
||||
@@ -187,20 +199,6 @@ private predicate superCall(CfgNodes::ExprNodes::CallCfgNode call, Module superC
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate instanceMethodCall(CfgNodes::ExprNodes::CallCfgNode call, Module tp, string method) {
|
||||
exists(DataFlow::Node receiver, Module m, boolean exact |
|
||||
methodCall(call, receiver, method) and
|
||||
receiver = trackInstance(m, exact)
|
||||
|
|
||||
tp = m
|
||||
or
|
||||
// When we don't know the exact type, it could be any sub class
|
||||
exact = false and
|
||||
tp.getSuperClass+() = m
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `self` belongs to module `m`. */
|
||||
pragma[nomagic]
|
||||
private predicate selfInModule(SelfVariable self, Module m) {
|
||||
@@ -318,6 +316,19 @@ private predicate extendCallModule(Module m, Module n) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a method available in module `m`, or in one of `m`'s transitive
|
||||
* sub classes when `exact = false`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Method lookupMethod(Module m, string name, boolean exact) {
|
||||
result = lookupMethod(m, name) and
|
||||
exact in [false, true]
|
||||
or
|
||||
result = lookupMethodInSubClasses(m, name) and
|
||||
exact = false
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
@@ -332,100 +343,139 @@ private module Cached {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
cached
|
||||
CfgScope getTarget(CfgNodes::ExprNodes::CallCfgNode call) {
|
||||
// Temporarily disable operation resolution (due to bad performance)
|
||||
not call.getExpr() instanceof Operation and
|
||||
(
|
||||
exists(string method |
|
||||
exists(Module tp |
|
||||
instanceMethodCall(call, tp, method) and
|
||||
result = lookupMethod(tp, method) and
|
||||
(
|
||||
if result.(Method).isPrivate()
|
||||
then
|
||||
call.getReceiver().getExpr() instanceof SelfVariableAccess and
|
||||
// For now, we restrict the scope of top-level declarations to their file.
|
||||
// This may remove some plausible targets, but also removes a lot of
|
||||
// implausible targets
|
||||
if result.getEnclosingModule() instanceof Toplevel
|
||||
then result.getFile() = call.getFile()
|
||||
else any()
|
||||
else any()
|
||||
) and
|
||||
if result.(Method).isProtected()
|
||||
then result = lookupMethod(call.getExpr().getEnclosingModule().getModule(), method)
|
||||
else any()
|
||||
)
|
||||
or
|
||||
// singleton method defined on an instance, e.g.
|
||||
// ```rb
|
||||
// c = C.new
|
||||
// def c.singleton; end # <- result
|
||||
// c.singleton # <- call
|
||||
// ```
|
||||
// or an `extend`ed instance, e.g.
|
||||
// ```rb
|
||||
// c = C.new
|
||||
// module M
|
||||
// def instance; end # <- result
|
||||
// end
|
||||
// c.extend M
|
||||
// c.instance # <- call
|
||||
// ```
|
||||
exists(DataFlow::Node receiver |
|
||||
methodCall(call, receiver, method) and
|
||||
receiver = trackSingletonMethodOnInstance(result, method)
|
||||
)
|
||||
or
|
||||
// singleton method defined on a module
|
||||
// or an `extend`ed module, e.g.
|
||||
// ```rb
|
||||
// module M
|
||||
// def instance; end # <- result
|
||||
// end
|
||||
// M.extend(M)
|
||||
// M.instance # <- call
|
||||
// ```
|
||||
exists(DataFlow::Node sourceNode, Module m |
|
||||
flowsToMethodCall(call, sourceNode, method) and
|
||||
result = lookupSingletonMethod(m, method)
|
||||
|
|
||||
// ```rb
|
||||
// def C.singleton; end # <- result
|
||||
// C.singleton # <- call
|
||||
// ```
|
||||
sourceNode = trackModuleAccess(m)
|
||||
or
|
||||
// ```rb
|
||||
// class C
|
||||
// def self.singleton; end # <- result
|
||||
// self.singleton # <- call
|
||||
// end
|
||||
// ```
|
||||
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), m)
|
||||
or
|
||||
// ```rb
|
||||
// class C
|
||||
// def self.singleton; end # <- result
|
||||
// def self.other
|
||||
// self.singleton # <- call
|
||||
// end
|
||||
// end
|
||||
// ```
|
||||
selfInMethod(sourceNode.(SsaSelfDefinitionNode).getVariable(), _, m.getSuperClass*())
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Module superClass, string method |
|
||||
superCall(call, superClass, method) and
|
||||
result = lookupMethod(superClass, method)
|
||||
)
|
||||
or
|
||||
result = yieldCall(call)
|
||||
pragma[nomagic]
|
||||
private Method lookupInstanceMethodCall(RelevantCall call, string method, boolean exact) {
|
||||
exists(Module tp, DataFlow::Node receiver |
|
||||
methodCall(call, pragma[only_bind_into](receiver), pragma[only_bind_into](method)) and
|
||||
receiver = trackInstance(tp, exact) and
|
||||
result = lookupMethod(tp, pragma[only_bind_into](method), exact)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isToplevelMethodInFile(Method m, File f) {
|
||||
m.getEnclosingModule() instanceof Toplevel and
|
||||
f = m.getFile()
|
||||
}
|
||||
|
||||
/** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */
|
||||
pragma[nomagic]
|
||||
private predicate selfInModuleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
|
||||
exists(SsaSelfDefinitionNode self |
|
||||
flowsToMethodCallReceiver(call, self, method) and
|
||||
selfInModule(self.getVariable(), m)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `self` access may be the receiver of `call` inside some singleton method, where
|
||||
* that method belongs to `m` or one of `m`'s transitive super classes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate selfInSingletonMethodFlowsToMethodCallReceiver(
|
||||
RelevantCall call, Module m, string method
|
||||
) {
|
||||
exists(SsaSelfDefinitionNode self, Module target, MethodBase caller |
|
||||
flowsToMethodCallReceiver(call, self, method) and
|
||||
target = m.getSuperClass*() and
|
||||
selfInMethod(self.getVariable(), caller, target) and
|
||||
singletonMethod(caller, _, _) and
|
||||
// Singleton methods declared in a block in the top-level may spuriously end up being seen as singleton
|
||||
// methods on Object, if the block is actually evaluated in the context of another class.
|
||||
// The 'self' inside such a singleton method could then be any class, leading to self-calls
|
||||
// being resolved to arbitrary singleton methods.
|
||||
// To remedy this, we do not allow following super-classes all the way to Object.
|
||||
not (m != target and target = TResolved("Object"))
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
CfgScope getTarget(RelevantCall call) {
|
||||
exists(string method |
|
||||
exists(boolean exact |
|
||||
result = lookupInstanceMethodCall(call, method, exact) and
|
||||
(
|
||||
if result.(Method).isPrivate()
|
||||
then
|
||||
call.getReceiver().getExpr() instanceof SelfVariableAccess and
|
||||
// For now, we restrict the scope of top-level declarations to their file.
|
||||
// This may remove some plausible targets, but also removes a lot of
|
||||
// implausible targets
|
||||
(
|
||||
isToplevelMethodInFile(result, call.getFile()) or
|
||||
not isToplevelMethodInFile(result, _)
|
||||
)
|
||||
else any()
|
||||
) and
|
||||
if result.(Method).isProtected()
|
||||
then result = lookupMethod(call.getExpr().getEnclosingModule().getModule(), method, exact)
|
||||
else any()
|
||||
)
|
||||
or
|
||||
// singleton method defined on an instance, e.g.
|
||||
// ```rb
|
||||
// c = C.new
|
||||
// def c.singleton; end # <- result
|
||||
// c.singleton # <- call
|
||||
// ```
|
||||
// or an `extend`ed instance, e.g.
|
||||
// ```rb
|
||||
// c = C.new
|
||||
// module M
|
||||
// def instance; end # <- result
|
||||
// end
|
||||
// c.extend M
|
||||
// c.instance # <- call
|
||||
// ```
|
||||
exists(DataFlow::Node receiver |
|
||||
methodCall(call, receiver, method) and
|
||||
receiver = trackSingletonMethodOnInstance(result, method)
|
||||
)
|
||||
or
|
||||
// singleton method defined on a module
|
||||
// or an `extend`ed module, e.g.
|
||||
// ```rb
|
||||
// module M
|
||||
// def instance; end # <- result
|
||||
// end
|
||||
// M.extend(M)
|
||||
// M.instance # <- call
|
||||
// ```
|
||||
exists(Module m | result = lookupSingletonMethod(m, method) |
|
||||
// ```rb
|
||||
// def C.singleton; end # <- result
|
||||
// C.singleton # <- call
|
||||
// ```
|
||||
moduleFlowsToMethodCallReceiver(call, m, method)
|
||||
or
|
||||
// ```rb
|
||||
// class C
|
||||
// def self.singleton; end # <- result
|
||||
// self.singleton # <- call
|
||||
// end
|
||||
// ```
|
||||
selfInModuleFlowsToMethodCallReceiver(call, m, method)
|
||||
or
|
||||
// ```rb
|
||||
// class C
|
||||
// def self.singleton; end # <- result
|
||||
// def self.other
|
||||
// self.singleton # <- call
|
||||
// end
|
||||
// end
|
||||
// ```
|
||||
selfInSingletonMethodFlowsToMethodCallReceiver(call, m, method)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Module superClass, string method |
|
||||
superCall(call, superClass, method) and
|
||||
result = lookupMethod(superClass, method)
|
||||
)
|
||||
or
|
||||
result = yieldCall(call)
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
cached
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
@@ -487,9 +537,14 @@ private DataFlow::LocalSourceNode trackModuleAccess(Module m, TypeTracker t) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* We exclude steps into `self` parameters, and instead rely on the type of the
|
||||
* enclosing module.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackModuleAccessRec(Module m, TypeTracker t, StepSummary summary) {
|
||||
StepSummary::step(trackModuleAccess(m, t), result, summary)
|
||||
StepSummary::step(trackModuleAccess(m, t), result, summary) and
|
||||
not result instanceof SelfParameterNode
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -551,19 +606,24 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
|
||||
tp = TResolved("Proc") and
|
||||
exact = true
|
||||
or
|
||||
exists(CfgNodes::ExprNodes::CallCfgNode call, DataFlow::LocalSourceNode sourceNode |
|
||||
flowsToMethodCall(call, sourceNode, "new") and
|
||||
exact = true and
|
||||
exists(RelevantCall call, DataFlow::LocalSourceNode sourceNode |
|
||||
flowsToMethodCallReceiver(call, sourceNode, "new") and
|
||||
n.asExpr() = call
|
||||
|
|
||||
// `C.new`
|
||||
sourceNode = trackModuleAccess(tp)
|
||||
sourceNode = trackModuleAccess(tp) and
|
||||
exact = true
|
||||
or
|
||||
// `self.new` inside a module
|
||||
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), tp)
|
||||
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), tp) and
|
||||
exact = true
|
||||
or
|
||||
// `self.new` inside a singleton method
|
||||
selfInMethod(sourceNode.(SsaSelfDefinitionNode).getVariable(), any(SingletonMethod sm), tp)
|
||||
exists(MethodBase target |
|
||||
selfInMethod(sourceNode.(SsaSelfDefinitionNode).getVariable(), target, tp) and
|
||||
singletonMethod(target, _, _) and
|
||||
exact = false
|
||||
)
|
||||
)
|
||||
or
|
||||
// `self` reference in method or top-level (but not in module or singleton method,
|
||||
@@ -834,10 +894,7 @@ pragma[nomagic]
|
||||
private predicate paramReturnFlow(
|
||||
DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary
|
||||
) {
|
||||
exists(
|
||||
CfgNodes::ExprNodes::CallCfgNode call, DataFlow::Node arg, DataFlow::ParameterNode p,
|
||||
Expr nodeFromPreExpr
|
||||
|
|
||||
exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr |
|
||||
TypeTrackerSpecific::callStep(call, arg, p) and
|
||||
nodeTo.getPreUpdateNode() = arg and
|
||||
summary.toString() = "return" and
|
||||
@@ -911,8 +968,7 @@ private predicate isInstanceLocalMustFlow(DataFlow::Node n, Module tp, boolean e
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContext0(
|
||||
CfgNodes::ExprNodes::CallCfgNode ctx, ArgumentNode arg, CfgNodes::ExprNodes::CallCfgNode call,
|
||||
Callable encl, string name
|
||||
RelevantCall ctx, ArgumentNode arg, RelevantCall call, Callable encl, string name
|
||||
) {
|
||||
exists(
|
||||
ParameterNodeImpl p, SsaDefinitionNode ssaNode, ParameterPosition ppos, ArgumentPosition apos
|
||||
@@ -920,7 +976,7 @@ private predicate mayBenefitFromCallContext0(
|
||||
// the receiver of `call` references `p`
|
||||
ssaNode = trackInstance(_, _) and
|
||||
LocalFlow::localFlowSsaParamInput(p, ssaNode) and
|
||||
flowsToMethodCall(pragma[only_bind_into](call), pragma[only_bind_into](ssaNode),
|
||||
flowsToMethodCallReceiver(pragma[only_bind_into](call), pragma[only_bind_into](ssaNode),
|
||||
pragma[only_bind_into](name)) and
|
||||
// `p` is a parameter of `encl`,
|
||||
encl = call.getScope() and
|
||||
@@ -943,8 +999,7 @@ private predicate mayBenefitFromCallContext0(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContext1(
|
||||
CfgNodes::ExprNodes::CallCfgNode ctx, CfgNodes::ExprNodes::CallCfgNode call, Callable encl,
|
||||
Module tp, boolean exact, string name
|
||||
RelevantCall ctx, RelevantCall call, Callable encl, Module tp, boolean exact, string name
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
mayBenefitFromCallContext0(ctx, pragma[only_bind_into](arg), call, encl,
|
||||
@@ -972,19 +1027,14 @@ predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
|
||||
pragma[nomagic]
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
// `ctx` can provide a potentially better type bound
|
||||
exists(CfgNodes::ExprNodes::CallCfgNode call0, Callable res |
|
||||
exists(RelevantCall call0, Callable res |
|
||||
call0 = call.asCall() and
|
||||
res = result.asCallable() and
|
||||
res = getTarget(call0) and // make sure to not include e.g. private methods
|
||||
exists(Module tp, Module m, boolean exact, string name |
|
||||
res = lookupMethod(tp, name) and
|
||||
exists(Module m, boolean exact, string name |
|
||||
res = lookupMethod(m, name, exact) and
|
||||
mayBenefitFromCallContext1(ctx.asCall(), pragma[only_bind_into](call0), _,
|
||||
pragma[only_bind_into](m), exact, pragma[only_bind_into](name))
|
||||
|
|
||||
tp = m
|
||||
or
|
||||
exact = false and
|
||||
tp.getSuperClass+() = m
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -838,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1700,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1742,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
|
||||
@@ -838,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1700,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1742,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
|
||||
@@ -838,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1700,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1742,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
|
||||
@@ -838,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1700,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1742,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
|
||||
@@ -838,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1700,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1742,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
|
||||
@@ -1003,6 +1003,8 @@ predicate jumpStep(Node pred, Node succ) {
|
||||
succ.(SsaDefinitionNode).getDefinition())
|
||||
or
|
||||
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(pred, succ)
|
||||
}
|
||||
|
||||
private ContentSet getKeywordContent(string name) {
|
||||
@@ -1165,8 +1167,8 @@ private module PostUpdateNodes {
|
||||
ExprPostUpdateNode() { this = TExprPostUpdateNode(e) }
|
||||
|
||||
override ExprNode getPreUpdateNode() {
|
||||
// For compund arguments, such as `m(if b then x else y)`, we want the leaf nodes
|
||||
// `[post] x` and `[post] y` to have two pre-update nodes: (1) the compund argument,
|
||||
// For compound arguments, such as `m(if b then x else y)`, we want the leaf nodes
|
||||
// `[post] x` and `[post] y` to have two pre-update nodes: (1) the compound argument,
|
||||
// `if b then x else y`; and the (2) the underlying expressions; `x` and `y`,
|
||||
// respectively.
|
||||
//
|
||||
|
||||
@@ -440,15 +440,24 @@ signature predicate guardChecksSig(CfgNodes::ExprCfgNode g, CfgNode e, boolean b
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
pragma[nomagic]
|
||||
private predicate guardChecksSsaDef(CfgNodes::ExprCfgNode g, boolean branch, Ssa::Definition def) {
|
||||
guardChecks(g, def.getARead(), branch)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate guardControlsSsaDef(
|
||||
CfgNodes::ExprCfgNode g, boolean branch, Ssa::Definition def, Node n
|
||||
) {
|
||||
def.getARead() = n.asExpr() and
|
||||
guardControlsBlock(g, n.asExpr().getBasicBlock(), branch)
|
||||
}
|
||||
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode() {
|
||||
exists(
|
||||
CfgNodes::ExprCfgNode g, boolean branch, CfgNodes::ExprCfgNode testedNode, Ssa::Definition def
|
||||
|
|
||||
def.getARead() = testedNode and
|
||||
def.getARead() = result.asExpr() and
|
||||
guardChecks(g, testedNode, branch) and
|
||||
guardControlsBlock(g, result.asExpr().getBasicBlock(), branch)
|
||||
exists(CfgNodes::ExprCfgNode g, boolean branch, Ssa::Definition def |
|
||||
guardChecksSsaDef(g, branch, def) and
|
||||
guardControlsSsaDef(g, branch, def, result)
|
||||
)
|
||||
or
|
||||
result.asExpr() = getAMaybeGuardedCapturedDef().getARead()
|
||||
|
||||
@@ -61,6 +61,20 @@ module Public {
|
||||
|
||||
/** Gets a summary component for a return of kind `rk`. */
|
||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||
|
||||
/** Gets a summary component for synthetic global `sg`. */
|
||||
SummaryComponent syntheticGlobal(SyntheticGlobal sg) {
|
||||
result = TSyntheticGlobalSummaryComponent(sg)
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthetic global. This represents some form of global state, which
|
||||
* summaries can read and write individually.
|
||||
*/
|
||||
abstract class SyntheticGlobal extends string {
|
||||
bindingset[this]
|
||||
SyntheticGlobal() { any() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,6 +270,7 @@ module Private {
|
||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||
TReturnSummaryComponent(ReturnKind rk) or
|
||||
TSyntheticGlobalSummaryComponent(SummaryComponent::SyntheticGlobal sg) or
|
||||
TWithoutContentSummaryComponent(ContentSet c) or
|
||||
TWithContentSummaryComponent(ContentSet c)
|
||||
|
||||
@@ -563,6 +578,11 @@ module Private {
|
||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
s.tail())), rk)
|
||||
)
|
||||
or
|
||||
exists(SummaryComponent::SyntheticGlobal sg |
|
||||
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||
result = getSyntheticGlobalType(sg)
|
||||
)
|
||||
)
|
||||
or
|
||||
n = summaryNodeOutputState(c, s) and
|
||||
@@ -582,6 +602,11 @@ module Private {
|
||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
s.tail())), pos)
|
||||
)
|
||||
or
|
||||
exists(SummaryComponent::SyntheticGlobal sg |
|
||||
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||
result = getSyntheticGlobalType(sg)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -692,6 +717,18 @@ module Private {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||
* from a flow summary.
|
||||
*/
|
||||
predicate summaryJumpStep(Node pred, Node succ) {
|
||||
exists(SummaryComponentStack s |
|
||||
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||
pred = summaryNodeOutputState(_, s) and
|
||||
succ = summaryNodeInputState(_, s)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||
* synthesized summary node, so in order for values to be cleared at calls
|
||||
@@ -871,18 +908,28 @@ module Private {
|
||||
AccessPathRange() { relevantSpec(this) }
|
||||
}
|
||||
|
||||
/** Holds if specification component `c` parses as parameter `n`. */
|
||||
/** Holds if specification component `token` parses as parameter `pos`. */
|
||||
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
||||
token.getName() = "Parameter" and
|
||||
pos = parseParamBody(token.getAnArgument())
|
||||
}
|
||||
|
||||
/** Holds if specification component `c` parses as argument `n`. */
|
||||
/** Holds if specification component `token` parses as argument `pos`. */
|
||||
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
||||
token.getName() = "Argument" and
|
||||
pos = parseArgBody(token.getAnArgument())
|
||||
}
|
||||
|
||||
/** Holds if specification component `token` parses as synthetic global `sg`. */
|
||||
predicate parseSynthGlobal(AccessPathToken token, string sg) {
|
||||
token.getName() = "SyntheticGlobal" and
|
||||
sg = token.getAnArgument()
|
||||
}
|
||||
|
||||
private class SyntheticGlobalFromAccessPath extends SummaryComponent::SyntheticGlobal {
|
||||
SyntheticGlobalFromAccessPath() { parseSynthGlobal(_, this) }
|
||||
}
|
||||
|
||||
private SummaryComponent interpretComponent(AccessPathToken token) {
|
||||
exists(ParameterPosition pos |
|
||||
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
||||
@@ -894,6 +941,10 @@ module Private {
|
||||
or
|
||||
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||
or
|
||||
exists(string sg |
|
||||
parseSynthGlobal(token, sg) and result = SummaryComponent::syntheticGlobal(sg)
|
||||
)
|
||||
or
|
||||
result = interpretComponentSpecific(token)
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) { an
|
||||
*/
|
||||
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
|
||||
|
||||
/** Gets the type of synthetic global `sg`. */
|
||||
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any() }
|
||||
|
||||
/**
|
||||
* Holds if an external flow summary exists for `c` with input specification
|
||||
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
||||
|
||||
@@ -64,7 +64,7 @@ predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, LocalVariable v) {
|
||||
i = -1
|
||||
}
|
||||
|
||||
/** Holds if `bb` contains a caputured read of variable `v`. */
|
||||
/** Holds if `bb` contains a captured read of variable `v`. */
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedVariableRead(Cfg::BasicBlock bb, LocalVariable v) {
|
||||
exists(LocalVariableReadAccess read |
|
||||
@@ -74,7 +74,7 @@ private predicate hasCapturedVariableRead(Cfg::BasicBlock bb, LocalVariable v) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `bb` contains a caputured write to variable `v`. */
|
||||
/** Holds if `bb` contains a captured write to variable `v`. */
|
||||
pragma[noinline]
|
||||
private predicate writesCapturedVariable(Cfg::BasicBlock bb, LocalVariable v) {
|
||||
exists(LocalVariableWriteAccess write |
|
||||
|
||||
@@ -417,7 +417,7 @@ module Rbi {
|
||||
override ReturnType getReturnType() { result = ReturnsCall.super.getReturnType() }
|
||||
}
|
||||
|
||||
/** A call to `void` that spcifies that a given method does not return a useful value. */
|
||||
/** A call to `void` that specifies that a given method does not return a useful value. */
|
||||
class MethodVoidCall extends MethodReturnsTypeCall instanceof VoidCall {
|
||||
override ReturnType getReturnType() { result = VoidCall.super.getReturnType() }
|
||||
}
|
||||
@@ -448,7 +448,7 @@ module Rbi {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `void` that spcifies that a given proc or block does not return
|
||||
* A call to `void` that specifies that a given proc or block does not return
|
||||
* a useful value.
|
||||
*/
|
||||
class ProcVoidCall extends ProcReturnsTypeCall instanceof VoidCall {
|
||||
|
||||
@@ -6,7 +6,7 @@ private import codeql.ruby.ast.internal.TreeSitter
|
||||
/** A source file that contains generated code. */
|
||||
abstract class GeneratedCodeFile extends RubyFile { }
|
||||
|
||||
/** A file contining comments suggesting it contains generated code. */
|
||||
/** A file continuing comments suggesting it contains generated code. */
|
||||
class GeneratedCommentFile extends GeneratedCodeFile {
|
||||
GeneratedCommentFile() { this = any(GeneratedCodeComment c).getLocation().getFile() }
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ class ActionControllerActionMethod extends Method, Http::Server::RequestHandler:
|
||||
|
||||
override string getFramework() { result = "ActionController" }
|
||||
|
||||
override string getAnHttpMethod() { result = this.getARoute().getHttpMethod() }
|
||||
|
||||
/** Gets a call to render from within this method. */
|
||||
Rails::RenderCall getARenderCall() { result.getParent+() = this }
|
||||
|
||||
@@ -139,6 +141,8 @@ class ParamsSource extends Http::Server::RequestInputAccess::Range {
|
||||
ParamsSource() { this.asExpr().getExpr() instanceof Rails::ParamsCall }
|
||||
|
||||
override string getSourceType() { result = "ActionController::Metal#params" }
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,6 +153,8 @@ class CookiesSource extends Http::Server::RequestInputAccess::Range {
|
||||
CookiesSource() { this.asExpr().getExpr() instanceof Rails::CookiesCall }
|
||||
|
||||
override string getSourceType() { result = "ActionController::Metal#cookies" }
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::cookieInputKind() }
|
||||
}
|
||||
|
||||
/** A call to `cookies` from within a controller. */
|
||||
@@ -161,6 +167,140 @@ private class ActionControllerParamsCall extends ActionControllerContextCall, Pa
|
||||
ActionControllerParamsCall() { this.getMethodName() = "params" }
|
||||
}
|
||||
|
||||
/** Modeling for `ActionDispatch::Request`. */
|
||||
private module Request {
|
||||
/**
|
||||
* A call to `request` from within a controller. This is an instance of
|
||||
* `ActionDispatch::Request`.
|
||||
*/
|
||||
private class RequestNode extends DataFlow::CallNode {
|
||||
RequestNode() {
|
||||
this.asExpr().getExpr() instanceof ActionControllerContextCall and
|
||||
this.getMethodName() = "request"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call on `request`.
|
||||
*/
|
||||
private class RequestMethodCall extends DataFlow::CallNode {
|
||||
RequestMethodCall() {
|
||||
any(RequestNode r).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver())
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class RequestInputAccess extends RequestMethodCall,
|
||||
Http::Server::RequestInputAccess::Range {
|
||||
override string getSourceType() { result = "ActionDispatch::Request#" + this.getMethodName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call on `request` which returns request parameters.
|
||||
*/
|
||||
private class ParametersCall extends RequestInputAccess {
|
||||
ParametersCall() {
|
||||
this.getMethodName() =
|
||||
[
|
||||
"parameters", "params", "GET", "POST", "query_parameters", "request_parameters",
|
||||
"filtered_parameters"
|
||||
]
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() {
|
||||
result = Http::Server::parameterInputKind()
|
||||
}
|
||||
}
|
||||
|
||||
/** A method call on `request` which returns part or all of the request path. */
|
||||
private class PathCall extends RequestInputAccess {
|
||||
PathCall() {
|
||||
this.getMethodName() =
|
||||
["path", "filtered_path", "fullpath", "original_fullpath", "original_url", "url"]
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::urlInputKind() }
|
||||
}
|
||||
|
||||
/** A method call on `request` which returns a specific request header. */
|
||||
private class HeadersCall extends RequestInputAccess {
|
||||
HeadersCall() {
|
||||
this.getMethodName() =
|
||||
[
|
||||
"authorization", "script_name", "path_info", "user_agent", "referer", "referrer",
|
||||
"host_authority", "content_type", "host", "hostname", "accept_encoding",
|
||||
"accept_language", "if_none_match", "if_none_match_etags", "content_mime_type"
|
||||
]
|
||||
or
|
||||
// Request headers are prefixed with `HTTP_` to distinguish them from
|
||||
// "headers" supplied by Rack middleware.
|
||||
this.getMethodName() = ["get_header", "fetch_header"] and
|
||||
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
|
||||
}
|
||||
|
||||
// TODO: each_header
|
||||
/**
|
||||
* A method call on `request` which returns part or all of the host.
|
||||
* This can be influenced by headers such as Host and X-Forwarded-Host.
|
||||
*/
|
||||
private class HostCall extends RequestInputAccess {
|
||||
HostCall() {
|
||||
this.getMethodName() =
|
||||
[
|
||||
"authority", "host", "host_authority", "host_with_port", "hostname", "forwarded_for",
|
||||
"forwarded_host", "port", "forwarded_port"
|
||||
]
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call on `request` which is influenced by one or more request
|
||||
* headers.
|
||||
*/
|
||||
private class HeaderTaintedCall extends RequestInputAccess {
|
||||
HeaderTaintedCall() {
|
||||
this.getMethodName() = ["media_type", "media_type_params", "content_charset", "base_url"]
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
|
||||
}
|
||||
|
||||
/** A method call on `request` which returns the request body. */
|
||||
private class BodyCall extends RequestInputAccess {
|
||||
BodyCall() { this.getMethodName() = ["body", "raw_post"] }
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call on `request` which returns the rack env.
|
||||
* This is a hash containing all the information about the request. Values
|
||||
* under keys starting with `HTTP_` are user-controlled.
|
||||
*/
|
||||
private class EnvCall extends RequestMethodCall {
|
||||
EnvCall() { this.getMethodName() = ["env", "filtered_env"] }
|
||||
}
|
||||
|
||||
/**
|
||||
* A read of a user-controlled parameter from the request env.
|
||||
*/
|
||||
private class EnvHttpAccess extends DataFlow::CallNode, Http::Server::RequestInputAccess::Range {
|
||||
EnvHttpAccess() {
|
||||
any(EnvCall c).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver()) and
|
||||
this.getMethodName() = "[]" and
|
||||
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
|
||||
|
||||
override string getSourceType() { result = "ActionDispatch::Request#env[]" }
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `render` from within a controller. */
|
||||
private class ActionControllerRenderCall extends ActionControllerContextCall, RenderCallImpl {
|
||||
ActionControllerRenderCall() { this.getMethodName() = "render" }
|
||||
@@ -171,14 +311,6 @@ private class ActionControllerRenderToCall extends ActionControllerContextCall,
|
||||
ActionControllerRenderToCall() { this.getMethodName() = ["render_to_body", "render_to_string"] }
|
||||
}
|
||||
|
||||
/** A call to `html_safe` from within a controller. */
|
||||
private class ActionControllerHtmlSafeCall extends HtmlSafeCallImpl {
|
||||
ActionControllerHtmlSafeCall() {
|
||||
this.getMethodName() = "html_safe" and
|
||||
this.getEnclosingModule() instanceof ActionControllerControllerClass
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `html_escape` from within a controller. */
|
||||
private class ActionControllerHtmlEscapeCall extends HtmlEscapeCallImpl {
|
||||
ActionControllerHtmlEscapeCall() {
|
||||
@@ -376,8 +508,11 @@ private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetti
|
||||
*/
|
||||
private class SendFile extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
SendFile() {
|
||||
this.asExpr().getExpr() instanceof ActionControllerContextCall and
|
||||
this.getMethodName() = "send_file"
|
||||
this.getMethodName() = "send_file" and
|
||||
(
|
||||
this.asExpr().getExpr() instanceof ActionControllerContextCall or
|
||||
this.getReceiver().asExpr().getExpr() instanceof Response::ResponseCall
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
@@ -502,3 +637,94 @@ private module ParamsSummaries {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides modeling for `ActionDispatch::Response`, which represents an HTTP
|
||||
* response.
|
||||
*/
|
||||
private module Response {
|
||||
class ResponseCall extends ActionControllerContextCall {
|
||||
ResponseCall() { this.getMethodName() = "response" }
|
||||
}
|
||||
|
||||
class BodyWrite extends DataFlow::CallNode, Http::Server::HttpResponse::Range {
|
||||
BodyWrite() {
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() = "body="
|
||||
}
|
||||
|
||||
override DataFlow::Node getBody() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
||||
|
||||
override string getMimetypeDefault() { result = "text/http" }
|
||||
}
|
||||
|
||||
class SendFileCall extends DataFlow::CallNode, Http::Server::HttpResponse::Range {
|
||||
SendFileCall() {
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() = "send_file"
|
||||
}
|
||||
|
||||
override DataFlow::Node getBody() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
||||
|
||||
override string getMimetypeDefault() { result = "application/octet-stream" }
|
||||
}
|
||||
|
||||
class HeaderWrite extends DataFlow::CallNode, Http::Server::HeaderWriteAccess::Range {
|
||||
HeaderWrite() {
|
||||
// response.header[key] = val
|
||||
// response.headers[key] = val
|
||||
exists(MethodCall headerCall |
|
||||
headerCall.getMethodName() = ["header", "headers"] and
|
||||
headerCall.getReceiver() instanceof ResponseCall
|
||||
|
|
||||
this.getReceiver().asExpr().getExpr() = headerCall and
|
||||
this.getMethodName() = "[]="
|
||||
)
|
||||
or
|
||||
// response.set_header(key) = val
|
||||
// response[header] = val
|
||||
// response.add_header(key, val)
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() = ["set_header", "[]=", "add_header"]
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = this.getArgument(0).asExpr().getConstantValue().getString()
|
||||
}
|
||||
|
||||
override DataFlow::Node getValue() { result = this.getArgument(1) }
|
||||
}
|
||||
|
||||
class SpecificHeaderWrite extends DataFlow::CallNode, Http::Server::HeaderWriteAccess::Range {
|
||||
SpecificHeaderWrite() {
|
||||
// response.<method> = val
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() =
|
||||
[
|
||||
"location=", "cache_control=", "_cache_control=", "etag=", "charset=", "content_type=",
|
||||
"date=", "last_modified=", "weak_etag=", "strong_etag="
|
||||
]
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
this.getMethodName() = "location=" and result = "location"
|
||||
or
|
||||
this.getMethodName() = ["_cache_control=", "cache_control="] and result = "cache-control"
|
||||
or
|
||||
this.getMethodName() = ["etag=", "weak_etag=", "strong_etag="] and result = "etag"
|
||||
or
|
||||
// sets the charset part of the content-type header
|
||||
this.getMethodName() = ["charset=", "content_type="] and result = "content-type"
|
||||
or
|
||||
this.getMethodName() = "date=" and result = "date"
|
||||
or
|
||||
this.getMethodName() = "last_modified=" and result = "last-modified"
|
||||
}
|
||||
|
||||
override DataFlow::Node getValue() { result = this.getArgument(0) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,6 @@ predicate inActionViewContext(AstNode n) {
|
||||
n.getLocation().getFile() instanceof ErbFile
|
||||
}
|
||||
|
||||
/** A call to `html_safe` from within a template. */
|
||||
private class ActionViewHtmlSafeCall extends HtmlSafeCallImpl {
|
||||
ActionViewHtmlSafeCall() { this.getMethodName() = "html_safe" and inActionViewContext(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a Rails method that escapes HTML.
|
||||
*/
|
||||
|
||||
30
ruby/ql/lib/codeql/ruby/frameworks/ActiveJob.qll
Normal file
30
ruby/ql/lib/codeql/ruby/frameworks/ActiveJob.qll
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Modeling for `ActiveJob`, a framweork for declaring and enqueueing jobs that
|
||||
* ships with Rails.
|
||||
* https://rubygems.org/gems/activejob
|
||||
*/
|
||||
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
|
||||
/** Modeling for `ActiveJob`. */
|
||||
module ActiveJob {
|
||||
/**
|
||||
* `ActiveJob::Serializers`
|
||||
*/
|
||||
module Serializers {
|
||||
/**
|
||||
* A call to `ActiveJob::Serializers.deserialize`, which interprets part of
|
||||
* its argument as a Ruby constant.
|
||||
*/
|
||||
class DeserializeCall extends DataFlow::CallNode, CodeExecution::Range {
|
||||
DeserializeCall() {
|
||||
this =
|
||||
API::getTopLevelMember("ActiveJob").getMember("Serializers").getAMethodCall("deserialize")
|
||||
}
|
||||
|
||||
override DataFlow::Node getCode() { result = this.getArgument(0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,6 +140,25 @@ module ActiveSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type summaries for extensions to the `Pathname` module.
|
||||
*/
|
||||
private class PathnameTypeSummary extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package1;type1;package2;type2;path
|
||||
// Pathname#existence : Pathname
|
||||
row = ";Pathname;;Pathname;Method[existence].ReturnValue"
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint flow summaries for extensions to the `Pathname` module. */
|
||||
private class PathnameTaintSummary extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
// Pathname#existence
|
||||
row = ";Pathname;Method[existence];Argument[self];ReturnValue;taint"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `ActiveSupport::SafeBuffer` wraps a string, providing HTML-safe methods
|
||||
* for concatenation.
|
||||
|
||||
@@ -14,6 +14,7 @@ import core.Hash
|
||||
import core.String
|
||||
import core.Regexp
|
||||
import core.IO
|
||||
import core.Digest
|
||||
|
||||
/**
|
||||
* A system command executed via subshell literal syntax.
|
||||
|
||||
@@ -84,6 +84,9 @@ private class GraphqlSchemaResolverClass extends ClassDeclaration {
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets an HTTP method that is supported for querying a GraphQL server. */
|
||||
private string getASupportedHttpMethod() { result = ["get", "post"] }
|
||||
|
||||
/**
|
||||
* A `ClassDeclaration` for a class that extends `GraphQL::Schema::Object`.
|
||||
* For example,
|
||||
@@ -120,7 +123,7 @@ class GraphqlSchemaObjectClass extends ClassDeclaration {
|
||||
* `GraphQL::Schema::RelayClassicMutation` or
|
||||
* `GraphQL::Schema::Resolver`.
|
||||
*
|
||||
* Both of these classes have an overrideable `resolve` instance
|
||||
* Both of these classes have an overridable `resolve` instance
|
||||
* method which can receive user input in order to resolve a query or mutation.
|
||||
*/
|
||||
private class GraphqlResolvableClass extends ClassDeclaration {
|
||||
@@ -144,7 +147,7 @@ private class GraphqlResolvableClass extends ClassDeclaration {
|
||||
*
|
||||
* ```rb
|
||||
* module Mutation
|
||||
* class NameAnInstrument < BaseMutationn
|
||||
* class NameAnInstrument < BaseMutation
|
||||
* argument :instrument_uuid, Types::Uuid,
|
||||
* required: true,
|
||||
* loads: ::Instrument,
|
||||
@@ -172,6 +175,8 @@ class GraphqlResolveMethod extends Method, Http::Server::RequestHandler::Range {
|
||||
|
||||
override string getFramework() { result = "GraphQL" }
|
||||
|
||||
override string getAnHttpMethod() { result = getASupportedHttpMethod() }
|
||||
|
||||
/** Gets the mutation class containing this method. */
|
||||
GraphqlResolvableClass getMutationClass() { result = resolvableClass }
|
||||
}
|
||||
@@ -188,7 +193,7 @@ class GraphqlResolveMethod extends Method, Http::Server::RequestHandler::Range {
|
||||
*
|
||||
* ```rb
|
||||
* module Mutation
|
||||
* class NameAnInstrument < BaseMutationn
|
||||
* class NameAnInstrument < BaseMutation
|
||||
* argument :instrument_uuid, Types::Uuid,
|
||||
* required: true,
|
||||
* loads: ::Instrument,
|
||||
@@ -219,6 +224,8 @@ class GraphqlLoadMethod extends Method, Http::Server::RequestHandler::Range {
|
||||
|
||||
override string getFramework() { result = "GraphQL" }
|
||||
|
||||
override string getAnHttpMethod() { result = getASupportedHttpMethod() }
|
||||
|
||||
/** Gets the mutation class containing this method. */
|
||||
GraphqlResolvableClass getMutationClass() { result = resolvableClass }
|
||||
}
|
||||
@@ -388,6 +395,8 @@ class GraphqlFieldResolutionMethod extends Method, Http::Server::RequestHandler:
|
||||
|
||||
override string getFramework() { result = "GraphQL" }
|
||||
|
||||
override string getAnHttpMethod() { result = getASupportedHttpMethod() }
|
||||
|
||||
/** Gets the class containing this method. */
|
||||
GraphqlSchemaObjectClass getGraphqlClass() { result = schemaObjectClass }
|
||||
}
|
||||
|
||||
@@ -16,10 +16,13 @@ private import codeql.ruby.security.OpenSSL
|
||||
*/
|
||||
module Rails {
|
||||
/**
|
||||
* DEPRECATED: Any call to `html_safe` is considered an XSS sink.
|
||||
* A method call on a string to mark it as HTML safe for Rails. Strings marked
|
||||
* as such will not be automatically escaped when inserted into HTML.
|
||||
*/
|
||||
class HtmlSafeCall extends MethodCall instanceof HtmlSafeCallImpl { }
|
||||
deprecated class HtmlSafeCall extends MethodCall {
|
||||
HtmlSafeCall() { this.getMethodName() = "html_safe" }
|
||||
}
|
||||
|
||||
/** A call to a Rails method to escape HTML. */
|
||||
class HtmlEscapeCall extends MethodCall instanceof HtmlEscapeCallImpl { }
|
||||
@@ -71,6 +74,21 @@ module Rails {
|
||||
|
||||
/** A render call that does not automatically set the HTTP response body. */
|
||||
class RenderToCall extends MethodCall instanceof RenderToCallImpl { }
|
||||
|
||||
/**
|
||||
* A `render` call seen as a file system access.
|
||||
*/
|
||||
private class RenderAsFileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
RenderAsFileSystemAccess() {
|
||||
exists(MethodCall call | this.asExpr().getExpr() = call |
|
||||
call instanceof RenderCall
|
||||
or
|
||||
call instanceof RenderToCall
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getKeywordArgument("file") }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
34
ruby/ql/lib/codeql/ruby/frameworks/core/Digest.qll
Normal file
34
ruby/ql/lib/codeql/ruby/frameworks/core/Digest.qll
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Provides modeling for the `Digest` module.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
|
||||
/** Gets an API node for a Digest class that hashes using `algo`. */
|
||||
private API::Node digest(Cryptography::HashingAlgorithm algo) {
|
||||
exists(string name | result = API::getTopLevelMember("Digest").getMember(name) |
|
||||
name = ["MD5", "SHA1", "SHA2", "RMD160"] and
|
||||
algo.matchesName(name)
|
||||
)
|
||||
}
|
||||
|
||||
/** A call that hashes some input using a hashing algorithm from the `Digest` module. */
|
||||
private class DigestCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Cryptography::HashingAlgorithm algo;
|
||||
|
||||
DigestCall() {
|
||||
this = digest(algo).getAMethodCall(["hexdigest", "base64digest", "bubblebabble"])
|
||||
or
|
||||
this = digest(algo).getAMethodCall("file") // it's directly hashing the contents of a file, but that's close enough for us.
|
||||
or
|
||||
this = digest(algo).getInstance().getAMethodCall(["digest", "update", "<<"])
|
||||
}
|
||||
|
||||
override Cryptography::HashingAlgorithm getAlgorithm() { result = algo }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
@@ -95,7 +95,7 @@ module IO {
|
||||
* popen([env,] cmd, mode="r" [, opt]) -> io
|
||||
* popen([env,] cmd, mode="r" [, opt]) {|io| block } -> obj
|
||||
* ```
|
||||
* `IO.popen` does different things based on the the value of `cmd`:
|
||||
* `IO.popen` does different things based on the value of `cmd`:
|
||||
* ```
|
||||
* "-" : fork
|
||||
* commandline : command line string which is passed to a shell
|
||||
|
||||
@@ -39,7 +39,8 @@ class FaradayHttpRequest extends Http::Client::Request::Range, DataFlow::CallNod
|
||||
API::getTopLevelMember("Faraday").getMember("Connection").getInstance()
|
||||
] and
|
||||
requestNode =
|
||||
connectionNode.getReturn(["get", "head", "delete", "post", "put", "patch", "trace"]) and
|
||||
connectionNode
|
||||
.getReturn(["get", "head", "delete", "post", "put", "patch", "trace", "run_request"]) and
|
||||
this = requestNode.asSource() and
|
||||
connectionUse = connectionNode.asSource()
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class HttpClientRequest extends Http::Client::Request::Range, DataFlow::CallNode
|
||||
[
|
||||
// One-off requests
|
||||
API::getTopLevelMember("HTTPClient"),
|
||||
// Conncection re-use
|
||||
// Connection re-use
|
||||
API::getTopLevelMember("HTTPClient").getInstance()
|
||||
] and
|
||||
requestNode = connectionNode.getReturn(method) and
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
private import codeql.ruby.AST
|
||||
|
||||
abstract class HtmlSafeCallImpl extends MethodCall { }
|
||||
|
||||
abstract class HtmlEscapeCallImpl extends MethodCall { }
|
||||
|
||||
abstract class RenderCallImpl extends MethodCall { }
|
||||
|
||||
@@ -241,7 +241,7 @@ abstract class RegExp extends Ast::StringlikeLiteral {
|
||||
|
||||
/**
|
||||
* Helper predicate for `escapingChar`.
|
||||
* In order to avoid negative recusrion, we return a boolean.
|
||||
* In order to avoid negative recursion, we return a boolean.
|
||||
* This way, we can refer to `escaping(pos - 1).booleanNot()`
|
||||
* rather than to a negated version of `escaping(pos)`.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Provides precicates for reasoning about bad tag filter vulnerabilities.
|
||||
* Provides predicates for reasoning about bad tag filter vulnerabilities.
|
||||
*/
|
||||
|
||||
import regexp.RegexpMatching
|
||||
@@ -65,7 +65,7 @@ predicate isBadRegexpFilter(HtmlMatchingRegExp regexp, string msg) {
|
||||
regexp.matches("<!-- foo --!>") and
|
||||
exists(int a, int b | a != b |
|
||||
regexp.fillsCaptureGroup("<!-- foo -->", a) and
|
||||
// <!-- foo --> might be ambigously parsed (matching both capture groups), and that is ok here.
|
||||
// <!-- foo --> might be ambiguously parsed (matching both capture groups), and that is ok here.
|
||||
regexp.fillsCaptureGroup("<!-- foo --!>", b) and
|
||||
not regexp.fillsCaptureGroup("<!-- foo --!>", a) and
|
||||
msg =
|
||||
|
||||
36
ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll
Normal file
36
ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Provides utility classes and predicates for reasoning about `Kernel.open` and related methods.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.frameworks.core.Kernel::Kernel
|
||||
|
||||
/** A call to a method that might access a file or start a process. */
|
||||
class AmbiguousPathCall extends DataFlow::CallNode {
|
||||
string name;
|
||||
|
||||
AmbiguousPathCall() {
|
||||
this.(KernelMethodCall).getMethodName() = "open" and
|
||||
name = "Kernel.open"
|
||||
or
|
||||
this = API::getTopLevelMember("IO").getAMethodCall("read") and
|
||||
not this = API::getTopLevelMember("File").getAMethodCall("read") and // needed in e.g. opal/opal, where some calls have both paths, but I'm not sure why
|
||||
name = "IO.read"
|
||||
}
|
||||
|
||||
/** Gets the name for the method being called. */
|
||||
string getName() { result = name }
|
||||
|
||||
/** Gets the name for a safer method that can be used instead. */
|
||||
string getReplacement() {
|
||||
result = "File.read" and name = "IO.read"
|
||||
or
|
||||
result = "File.open" and name = "Kernel.open"
|
||||
}
|
||||
|
||||
/** Gets the argument that specifies the path to be accessed. */
|
||||
DataFlow::Node getPathArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
@@ -581,3 +581,49 @@ private class CipherOperation extends Cryptography::CryptographicOperation::Rang
|
||||
result = cipherNode.getCipherMode().getBlockMode()
|
||||
}
|
||||
}
|
||||
|
||||
/** Predicates and classes modeling the `OpenSSL::Digest` module */
|
||||
private module Digest {
|
||||
private import codeql.ruby.ApiGraphs
|
||||
|
||||
/** A call that hashes some input using a hashing algorithm from the `OpenSSL::Digest` module. */
|
||||
private class DigestCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Cryptography::HashingAlgorithm algo;
|
||||
|
||||
DigestCall() {
|
||||
exists(API::MethodAccessNode call |
|
||||
call = API::getTopLevelMember("OpenSSL").getMember("Digest").getMethod("new")
|
||||
|
|
||||
this = call.getReturn().getAMethodCall(["digest", "update", "<<"]) and
|
||||
algo.matchesName(call.getCallNode()
|
||||
.getArgument(0)
|
||||
.asExpr()
|
||||
.getExpr()
|
||||
.getConstantValue()
|
||||
.getString())
|
||||
)
|
||||
}
|
||||
|
||||
override Cryptography::HashingAlgorithm getAlgorithm() { result = algo }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
|
||||
/** A call to `OpenSSL::Digest.digest` that hashes input directly without constructing a digest instance. */
|
||||
private class DigestCallDirect extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Cryptography::HashingAlgorithm algo;
|
||||
|
||||
DigestCallDirect() {
|
||||
this = API::getTopLevelMember("OpenSSL").getMember("Digest").getMethod("digest").getCallNode() and
|
||||
algo.matchesName(this.getArgument(0).asExpr().getExpr().getConstantValue().getString())
|
||||
}
|
||||
|
||||
override Cryptography::HashingAlgorithm getAlgorithm() { result = algo }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(1) }
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,144 @@
|
||||
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.DataFlow
|
||||
import codeql.ruby.security.internal.SensitiveDataHeuristics
|
||||
private import HeuristicNames
|
||||
private import codeql.ruby.CFG
|
||||
|
||||
/** An expression that might contain sensitive data. */
|
||||
cached
|
||||
abstract class SensitiveNode extends DataFlow::Node {
|
||||
/** Gets a human-readable description of this expression for use in alert messages. */
|
||||
cached
|
||||
abstract string describe();
|
||||
|
||||
/** Gets a classification of the kind of sensitive data this expression might contain. */
|
||||
cached
|
||||
abstract SensitiveDataClassification getClassification();
|
||||
}
|
||||
|
||||
/** A method call that might produce sensitive data. */
|
||||
class SensitiveCall extends SensitiveNode instanceof DataFlow::CallNode {
|
||||
SensitiveDataClassification classification;
|
||||
|
||||
SensitiveCall() {
|
||||
classification = this.getMethodName().(SensitiveDataMethodName).getClassification()
|
||||
or
|
||||
// This is particularly to pick up methods with an argument like "password", which
|
||||
// may indicate a lookup.
|
||||
exists(string s | super.getArgument(_).asExpr().getConstantValue().isStringlikeValue(s) |
|
||||
nameIndicatesSensitiveData(s, classification)
|
||||
)
|
||||
}
|
||||
|
||||
override string describe() { result = "a call to " + super.getMethodName() }
|
||||
|
||||
override SensitiveDataClassification getClassification() { result = classification }
|
||||
}
|
||||
|
||||
/** An access to a variable or hash value that might contain sensitive data. */
|
||||
abstract class SensitiveVariableAccess extends SensitiveNode {
|
||||
string name;
|
||||
|
||||
SensitiveVariableAccess() {
|
||||
this.asExpr().(CfgNodes::ExprNodes::VariableAccessCfgNode).getExpr().getVariable().hasName(name)
|
||||
or
|
||||
this.asExpr()
|
||||
.(CfgNodes::ExprNodes::ElementReferenceCfgNode)
|
||||
.getAnArgument()
|
||||
.getConstantValue()
|
||||
.isStringlikeValue(name)
|
||||
}
|
||||
|
||||
override string describe() { result = "an access to " + name }
|
||||
}
|
||||
|
||||
/** A write to a location that might contain sensitive data. */
|
||||
abstract class SensitiveWrite extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* Holds if `node` is a write to a variable or hash value named `name`.
|
||||
*
|
||||
* Helper predicate factored out for performance,
|
||||
* to filter `name` as much as possible before using it in
|
||||
* regex matching.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate writesProperty(DataFlow::Node node, string name) {
|
||||
exists(VariableWriteAccess vwa | vwa.getVariable().getName() = name |
|
||||
node.asExpr().getExpr() = vwa
|
||||
)
|
||||
or
|
||||
// hash value assignment
|
||||
node.(DataFlow::CallNode).getMethodName() = "[]=" and
|
||||
node.(DataFlow::CallNode).getArgument(0).asExpr().getConstantValue().isStringlikeValue(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Instance and class variable names are reported with their respective `@`
|
||||
* and `@@` prefixes. This predicate strips these prefixes.
|
||||
*/
|
||||
bindingset[name]
|
||||
private string unprefixedVariableName(string name) { result = name.regexpReplaceAll("^@*", "") }
|
||||
|
||||
/** A write to a variable or property that might contain sensitive data. */
|
||||
private class BasicSensitiveWrite extends SensitiveWrite {
|
||||
SensitiveDataClassification classification;
|
||||
|
||||
BasicSensitiveWrite() {
|
||||
exists(string name |
|
||||
/*
|
||||
* PERFORMANCE OPTIMISATION:
|
||||
* `nameIndicatesSensitiveData` performs a `regexpMatch` on `name`.
|
||||
* To carry out a regex match, we must first compute the Cartesian product
|
||||
* of all possible `name`s and regexes, then match.
|
||||
* To keep this product as small as possible,
|
||||
* we want to filter `name` as much as possible before the product.
|
||||
*
|
||||
* Do this by factoring out a helper predicate containing the filtering
|
||||
* logic that restricts `name`. This helper predicate will get picked first
|
||||
* in the join order, since it is the only call here that binds `name`.
|
||||
*/
|
||||
|
||||
writesProperty(this, name) and
|
||||
nameIndicatesSensitiveData(unprefixedVariableName(name), classification)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a classification of the kind of sensitive data the write might handle. */
|
||||
SensitiveDataClassification getClassification() { result = classification }
|
||||
}
|
||||
|
||||
/** An access to a variable or hash value that might contain sensitive data. */
|
||||
private class BasicSensitiveVariableAccess extends SensitiveVariableAccess {
|
||||
SensitiveDataClassification classification;
|
||||
|
||||
BasicSensitiveVariableAccess() {
|
||||
nameIndicatesSensitiveData(unprefixedVariableName(name), classification)
|
||||
}
|
||||
|
||||
override SensitiveDataClassification getClassification() { result = classification }
|
||||
}
|
||||
|
||||
/** A method name that suggests it may be sensitive. */
|
||||
abstract class SensitiveMethodName extends string {
|
||||
SensitiveMethodName() { this = any(MethodBase m).getName() }
|
||||
}
|
||||
|
||||
/** A method name that suggests it may produce sensitive data. */
|
||||
abstract class SensitiveDataMethodName extends SensitiveMethodName {
|
||||
/** Gets a classification of the kind of sensitive data this method may produce. */
|
||||
abstract SensitiveDataClassification getClassification();
|
||||
}
|
||||
|
||||
/** A method name that might return sensitive credential data. */
|
||||
class CredentialsMethodName extends SensitiveDataMethodName {
|
||||
SensitiveDataClassification classification;
|
||||
|
||||
CredentialsMethodName() { nameIndicatesSensitiveData(this, classification) }
|
||||
|
||||
override SensitiveDataClassification getClassification() { result = classification }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensitive action, such as transfer of sensitive data.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Provides default sources and sinks for reasoning about sensitive data sourced
|
||||
* from the query string of a GET request, as well as extension points for
|
||||
* adding your own.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.security.SensitiveActions
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
|
||||
/**
|
||||
* Provides default sources and sinks for reasoning about sensitive data sourced
|
||||
* from the query string of a GET request, as well as extension points for
|
||||
* adding your own.
|
||||
*/
|
||||
module SensitiveGetQuery {
|
||||
/**
|
||||
* A data flow source representing data sourced from the query string in a
|
||||
* GET request handler.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node {
|
||||
/** Gets the request handler corresponding to this data source. */
|
||||
abstract Http::Server::RequestHandler getHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to data from the query string of a GET request as a data flow
|
||||
* source.
|
||||
*/
|
||||
private class RequestInputAccessSource extends Source instanceof Http::Server::RequestInputAccess {
|
||||
private Http::Server::RequestHandler handler;
|
||||
|
||||
RequestInputAccessSource() {
|
||||
handler = this.asExpr().getExpr().getEnclosingMethod() and
|
||||
handler.getAnHttpMethod() = "get" and
|
||||
this.getKind() = "parameter"
|
||||
}
|
||||
|
||||
override Http::Server::RequestHandler getHandler() { result = handler }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow sink suggesting a use of sensitive data.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/** A sensitive data node as a data flow sink. */
|
||||
private class SensitiveNodeSink extends Sink instanceof SensitiveNode {
|
||||
SensitiveNodeSink() {
|
||||
// User names and other similar information is not sensitive in this context.
|
||||
not this.getClassification() = SensitiveDataClassification::id()
|
||||
}
|
||||
}
|
||||
}
|
||||
31
ruby/ql/lib/codeql/ruby/security/SensitiveGetQueryQuery.qll
Normal file
31
ruby/ql/lib/codeql/ruby/security/SensitiveGetQueryQuery.qll
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting flow of query string
|
||||
* data to sensitive actions in GET query request handlers.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if `Configuration` is
|
||||
* needed, otherwise `SensitiveGetQueryCustomizations` should be imported
|
||||
* instead.
|
||||
*/
|
||||
|
||||
private import ruby
|
||||
private import codeql.ruby.TaintTracking
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting flow of query string
|
||||
* data to sensitive actions in GET query request handlers.
|
||||
*/
|
||||
module SensitiveGetQuery {
|
||||
import SensitiveGetQueryCustomizations::SensitiveGetQuery
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about use of sensitive data
|
||||
* from a GET request query string.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "SensitiveGetQuery" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.CFG
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
private import codeql.ruby.frameworks.ActiveJob
|
||||
private import codeql.ruby.frameworks.core.Module
|
||||
|
||||
module UnsafeDeserialization {
|
||||
/**
|
||||
@@ -199,4 +201,27 @@ module UnsafeDeserialization {
|
||||
toNode = callNode
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A argument in a call to `Module.const_get`, considered as a sink for unsafe
|
||||
* deserialization.
|
||||
*
|
||||
* Calls to `Module.const_get` can return arbitrary classes which can then be
|
||||
* instantiated.
|
||||
*/
|
||||
class ConstGetCallArgument extends Sink {
|
||||
ConstGetCallArgument() { this = any(Module::ModuleConstGetCallCodeExecution c).getCode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A argument in a call to `ActiveJob::Serializers.deserialize`, considered as
|
||||
* a sink for unsafe deserialization.
|
||||
*
|
||||
* This is roughly equivalent to a call to `Module.const_get`.
|
||||
*/
|
||||
class ActiveJobSerializersDeserializeArgument extends Sink {
|
||||
ActiveJobSerializersDeserializeArgument() {
|
||||
this = any(ActiveJob::Serializers::DeserializeCall c).getCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,9 @@ module UrlRedirect {
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
|
||||
class HttpRequestInputAccessAsSource extends Source, Http::Server::RequestInputAccess {
|
||||
HttpRequestInputAccessAsSource() { this.isThirdPartyControllable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A HTTP redirect response, considered as a flow sink.
|
||||
|
||||
@@ -62,10 +62,7 @@ private module Shared {
|
||||
*/
|
||||
class HtmlSafeCallAsSink extends Sink {
|
||||
HtmlSafeCallAsSink() {
|
||||
exists(Rails::HtmlSafeCall c, ErbOutputDirective d |
|
||||
this.asExpr().getExpr() = c.getReceiver() and
|
||||
c = d.getTerminalStmt()
|
||||
)
|
||||
this = any(DataFlow::CallNode call | call.getMethodName() = "html_safe").getReceiver()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +102,17 @@ private module Shared {
|
||||
}
|
||||
}
|
||||
|
||||
/** A write to an HTTP response header, considered as a flow sink. */
|
||||
class HeaderWriteAsSink extends Sink {
|
||||
HeaderWriteAsSink() {
|
||||
exists(Http::Server::HeaderWriteAccess a |
|
||||
a.getName() = ["content-type", "access-control-allow-origin"]
|
||||
|
|
||||
this = a.getValue()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An HTML escaping, considered as a sanitizer.
|
||||
*/
|
||||
@@ -312,9 +320,11 @@ module ReflectedXss {
|
||||
deprecated predicate isAdditionalXSSTaintStep = isAdditionalXssTaintStep/2;
|
||||
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source.
|
||||
* A HTTP request input, considered as a flow source.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
|
||||
class HttpRequestInputAccessAsSource extends Source, Http::Server::RequestInputAccess {
|
||||
HttpRequestInputAccessAsSource() { this.isThirdPartyControllable() }
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ReflectedXss */
|
||||
@@ -329,17 +339,13 @@ private module OrmTracking {
|
||||
|
||||
override predicate isSource(DataFlow2::Node source) { source instanceof OrmInstantiation }
|
||||
|
||||
// Select any call node and narrow down later
|
||||
override predicate isSink(DataFlow2::Node sink) { sink instanceof DataFlow2::CallNode }
|
||||
// Select any call receiver and narrow down later
|
||||
override predicate isSink(DataFlow2::Node sink) {
|
||||
sink = any(DataFlow2::CallNode c).getReceiver()
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow2::Node node1, DataFlow2::Node node2) {
|
||||
Shared::isAdditionalXssFlowStep(node1, node2)
|
||||
or
|
||||
// Propagate flow through arbitrary method calls
|
||||
node2.(DataFlow2::CallNode).getReceiver() = node1
|
||||
or
|
||||
// Propagate flow through "or" expressions `or`/`||`
|
||||
node2.asExpr().getExpr().(LogicalOrExpr).getAnOperand() = node1.asExpr().getExpr()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,10 +378,9 @@ module StoredXss {
|
||||
|
||||
private class OrmFieldAsSource extends Source instanceof DataFlow2::CallNode {
|
||||
OrmFieldAsSource() {
|
||||
exists(OrmTracking::Configuration subConfig, DataFlow2::CallNode subSrc, MethodCall call |
|
||||
subConfig.hasFlow(subSrc, this) and
|
||||
call = this.asExpr().getExpr() and
|
||||
subSrc.(OrmInstantiation).methodCallMayAccessField(call.getMethodName())
|
||||
exists(OrmTracking::Configuration subConfig, DataFlow2::CallNode subSrc |
|
||||
subConfig.hasFlow(subSrc, this.getReceiver()) and
|
||||
subSrc.(OrmInstantiation).methodCallMayAccessField(this.getMethodName())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ private predicate isFork(State q, InputSymbol s1, InputSymbol s2, State r1, Stat
|
||||
//
|
||||
// We additionally require that the there exists another InfiniteRepetitionQuantifier `mid` on the path from `q` to itself.
|
||||
// This is done to avoid flagging regular expressions such as `/(a?)*b/` - that only has polynomial runtime, and is detected by `js/polynomial-redos`.
|
||||
// The below code is therefore a heuritic, that only flags regular expressions such as `/(a*)*b/`,
|
||||
// The below code is therefore a heuristic, that only flags regular expressions such as `/(a*)*b/`,
|
||||
// and does not flag regular expressions such as `/(a?b?)c/`, but the latter pattern is not used frequently.
|
||||
r1 = r2 and
|
||||
q1 = q2 and
|
||||
|
||||
@@ -59,8 +59,8 @@ predicate matchesEpsilon(RegExpTerm t) {
|
||||
/**
|
||||
* A lookahead/lookbehind that matches the empty string.
|
||||
*/
|
||||
class EmptyPositiveSubPatttern extends RegExpSubPattern {
|
||||
EmptyPositiveSubPatttern() {
|
||||
class EmptyPositiveSubPattern extends RegExpSubPattern {
|
||||
EmptyPositiveSubPattern() {
|
||||
(
|
||||
this instanceof RegExpPositiveLookahead
|
||||
or
|
||||
@@ -70,6 +70,9 @@ class EmptyPositiveSubPatttern extends RegExpSubPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `EmptyPositiveSubPattern` instead. */
|
||||
deprecated class EmptyPositiveSubPatttern = EmptyPositiveSubPattern;
|
||||
|
||||
/**
|
||||
* A branch in a disjunction that is the root node in a literal, or a literal
|
||||
* whose root node is not a disjunction.
|
||||
@@ -133,7 +136,7 @@ private predicate isCanonicalTerm(RelevantRegExpTerm term, string str) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string reperesentation of the flags used with the regular expression.
|
||||
* Gets a string representation of the flags used with the regular expression.
|
||||
* Only the flags that are relevant for the canonicalization are included.
|
||||
*/
|
||||
string getCanonicalizationFlags(RegExpTerm root) {
|
||||
@@ -334,7 +337,7 @@ private module CharacterClasses {
|
||||
)
|
||||
}
|
||||
|
||||
private string lowercaseLetter() { result = "abdcefghijklmnopqrstuvwxyz".charAt(_) }
|
||||
private string lowercaseLetter() { result = "abcdefghijklmnopqrstuvwxyz".charAt(_) }
|
||||
|
||||
private string upperCaseLetter() { result = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(_) }
|
||||
|
||||
@@ -697,9 +700,7 @@ predicate delta(State q1, EdgeLabel lbl, State q2) {
|
||||
lbl = Epsilon() and q2 = Accept(getRoot(dollar))
|
||||
)
|
||||
or
|
||||
exists(EmptyPositiveSubPatttern empty | q1 = before(empty) |
|
||||
lbl = Epsilon() and q2 = after(empty)
|
||||
)
|
||||
exists(EmptyPositiveSubPattern empty | q1 = before(empty) | lbl = Epsilon() and q2 = after(empty))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1028,7 +1029,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
|
||||
* as the suffix "X" will cause both the regular expressions to be rejected.
|
||||
*
|
||||
* The string `w` is repeated any number of times because it needs to be
|
||||
* infinitely repeatedable for the attack to work.
|
||||
* infinitely repeatable for the attack to work.
|
||||
* For the regular expression `/((ab)+)*abab/` the accepting state is not reachable from the fork
|
||||
* using epsilon transitions. But any attempt at repeating `w` will end in a state that accepts all suffixes.
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@ import codeql.Locations
|
||||
private import codeql.ruby.ast.Literal as Ast
|
||||
|
||||
/**
|
||||
* Holds if `term` is an ecape class representing e.g. `\d`.
|
||||
* Holds if `term` is an escape class representing e.g. `\d`.
|
||||
* `clazz` is which character class it represents, e.g. "d" for `\d`.
|
||||
*/
|
||||
predicate isEscapeClass(RegExpTerm term, string clazz) {
|
||||
|
||||
@@ -106,6 +106,18 @@ module PolynomialReDoS {
|
||||
regexp.asExpr() = call.getReceiver() and
|
||||
this.asExpr() = call.getArgument(0)
|
||||
)
|
||||
or
|
||||
// a case-when statement
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode caseWhen |
|
||||
matchNode.asExpr() = caseWhen and
|
||||
this.asExpr() = caseWhen.getValue()
|
||||
|
|
||||
regexp.asExpr() =
|
||||
caseWhen.getBranch(_).(CfgNodes::ExprNodes::WhenClauseCfgNode).getPattern(_)
|
||||
or
|
||||
regexp.asExpr() =
|
||||
caseWhen.getBranch(_).(CfgNodes::ExprNodes::InClauseCfgNode).getPattern()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Provides precicates for reasoning about which strings are matched by a regular expression,
|
||||
* Provides predicates for reasoning about which strings are matched by a regular expression,
|
||||
* and for testing which capture groups are filled when a particular regexp matches a string.
|
||||
*/
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class StateTuple extends TStateTuple {
|
||||
StateTuple() { this = MkStateTuple(q1, q2, q3) }
|
||||
|
||||
/**
|
||||
* Gest a string repesentation of this tuple.
|
||||
* Gest a string representation of this tuple.
|
||||
*/
|
||||
string toString() { result = "(" + q1 + ", " + q2 + ", " + q3 + ")" }
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `rb/log-inection`, to detect cases where a malicious user may be able to forge log entries.
|
||||
* Added a new query, `rb/log-injection`, to detect cases where a malicious user may be able to forge log entries.
|
||||
* Added a new query, `rb/incomplete-multi-character-sanitization`. The query
|
||||
finds string transformations that do not replace all occurrences of a
|
||||
multi-character substring.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `rb/sensitive-get-query`, to detect cases where sensitive data is read from the query parameters of an HTTP `GET` request.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `rb/non-constant-kernel-open`, to detect uses of Kernel.open and related methods with non-constant values.
|
||||
4
ruby/ql/src/change-notes/2022-10-12-rails-render-file.md
Normal file
4
ruby/ql/src/change-notes/2022-10-12-rails-render-file.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `rb/path-injection` query now treats the `file:` argument of the Rails `render` method as a sink.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* HTTP response header and body writes via `ActionDispatch::Response` are now
|
||||
recognized.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `rb/log-inection`, to detect cases where a malicious user may be able to forge log entries.
|
||||
* Added a new query, `rb/log-injection`, to detect cases where a malicious user may be able to forge log entries.
|
||||
* Added a new query, `rb/incomplete-multi-character-sanitization`. The query
|
||||
finds string transformations that do not replace all occurrences of a
|
||||
multi-character substring.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Manually checking http verb instead of using built in rails routes and protections
|
||||
* @description Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods.
|
||||
* @description Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 5.0
|
||||
@@ -93,4 +93,4 @@ class HttpVerbConfig extends TaintTracking::Configuration {
|
||||
from HttpVerbConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods."
|
||||
"Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods."
|
||||
|
||||
46
ruby/ql/src/queries/security/cwe-078/KernelOpen.inc.qhelp
Normal file
46
ruby/ql/src/queries/security/cwe-078/KernelOpen.inc.qhelp
Normal file
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>If <code>Kernel.open</code> is given a file name that starts with a <code>|</code>
|
||||
character, it will execute the remaining string as a shell command. If a
|
||||
malicious user can control the file name, they can execute arbitrary code.
|
||||
The same vulnerability applies to <code>IO.read</code>.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use <code>File.open</code> instead of <code>Kernel.open</code>, as the former
|
||||
does not have this vulnerability. Similarly, use <code>File.read</code> instead
|
||||
of <code>IO.read</code>.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example shows code that calls <code>Kernel.open</code> on a
|
||||
user-supplied file path.
|
||||
</p>
|
||||
|
||||
<sample src="examples/kernel_open.rb" />
|
||||
|
||||
<p>Instead, <code>File.open</code> should be used, as in the following example.</p>
|
||||
|
||||
<sample src="examples/file_open.rb" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/Command_Injection">Command Injection</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Example CVE: <a href="https://www.ruby-lang.org/en/news/2021/05/02/os-command-injection-in-rdoc/">Command Injection in RDoc</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,46 +1,4 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>If <code>Kernel.open</code> is given a file name that starts with a <code>|</code>
|
||||
character, it will execute the remaining string as a shell command. If a
|
||||
malicious user can control the file name, they can execute arbitrary code.
|
||||
The same vulnerability applies to <code>IO.read</code>.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use <code>File.open</code> instead of <code>Kernel.open</code>, as the former
|
||||
does not have this vulnerability. Similarly, use <code>File.read</code> instead
|
||||
of <code>IO.read</code>.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example shows code that calls <code>Kernel.open</code> on a
|
||||
user-supplied file path.
|
||||
</p>
|
||||
|
||||
<sample src="examples/kernel_open.rb" />
|
||||
|
||||
<p>Instead, <code>File.open</code> should be used, as in the following example.</p>
|
||||
|
||||
<sample src="examples/file_open.rb" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/Command_Injection">Command Injection</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Example CVE: <a href="https://www.ruby-lang.org/en/news/2021/05/02/os-command-injection-in-rdoc/">Command Injection in RDoc</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
<include src="KernelOpen.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Use of `Kernel.open` or `IO.read`
|
||||
* @name Use of `Kernel.open` or `IO.read` with user-controlled input
|
||||
* @description Using `Kernel.open` or `IO.read` may allow a malicious
|
||||
* user to execute arbitrary system commands.
|
||||
* @kind path-problem
|
||||
@@ -14,39 +14,12 @@
|
||||
* external/cwe/cwe-073
|
||||
*/
|
||||
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.ApiGraphs
|
||||
import codeql.ruby.frameworks.core.Kernel::Kernel
|
||||
import codeql.ruby.TaintTracking
|
||||
import codeql.ruby.dataflow.BarrierGuards
|
||||
import codeql.ruby.dataflow.RemoteFlowSources
|
||||
import codeql.ruby.DataFlow
|
||||
import codeql.ruby.TaintTracking
|
||||
import codeql.ruby.dataflow.RemoteFlowSources
|
||||
import codeql.ruby.dataflow.BarrierGuards
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A method call that has a suggested replacement.
|
||||
*/
|
||||
abstract class Replacement extends DataFlow::CallNode {
|
||||
abstract string getFrom();
|
||||
|
||||
abstract string getTo();
|
||||
}
|
||||
|
||||
class KernelOpenCall extends KernelMethodCall, Replacement {
|
||||
KernelOpenCall() { this.getMethodName() = "open" }
|
||||
|
||||
override string getFrom() { result = "Kernel.open" }
|
||||
|
||||
override string getTo() { result = "File.open" }
|
||||
}
|
||||
|
||||
class IOReadCall extends DataFlow::CallNode, Replacement {
|
||||
IOReadCall() { this = API::getTopLevelMember("IO").getAMethodCall("read") }
|
||||
|
||||
override string getFrom() { result = "IO.read" }
|
||||
|
||||
override string getTo() { result = "File.read" }
|
||||
}
|
||||
import codeql.ruby.security.KernelOpenQuery
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "KernelOpen" }
|
||||
@@ -54,9 +27,7 @@ class Configuration extends TaintTracking::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(KernelOpenCall c | c.getArgument(0) = sink)
|
||||
or
|
||||
exists(IOReadCall c | c.getArgument(0) = sink)
|
||||
sink = any(AmbiguousPathCall r).getPathArgument()
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
@@ -73,5 +44,6 @@ where
|
||||
sourceNode = source.getNode() and
|
||||
call.getArgument(0) = sink.getNode()
|
||||
select sink.getNode(), source, sink,
|
||||
"This call to " + call.(Replacement).getFrom() + " depends on a $@. Replace it with " +
|
||||
call.(Replacement).getTo() + ".", source.getNode(), "user-provided value"
|
||||
"This call to " + call.(AmbiguousPathCall).getName() +
|
||||
" depends on a $@. Consider replacing it with " + call.(AmbiguousPathCall).getReplacement() +
|
||||
".", source.getNode(), "user-provided value"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="KernelOpen.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @name Use of `Kernel.open` or `IO.read` with a non-constant value
|
||||
* @description Using `Kernel.open` or `IO.read` may allow a malicious
|
||||
* user to execute arbitrary system commands.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.5
|
||||
* @precision high
|
||||
* @id rb/non-constant-kernel-open
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-078
|
||||
* external/cwe/cwe-088
|
||||
* external/cwe/cwe-073
|
||||
*/
|
||||
|
||||
import codeql.ruby.security.KernelOpenQuery
|
||||
import codeql.ruby.ast.Literal
|
||||
|
||||
from AmbiguousPathCall call
|
||||
where
|
||||
// there is not a constant string argument
|
||||
not exists(call.getPathArgument().asExpr().getExpr().getConstantValue()) and
|
||||
// if it's a format string, then the first argument is not a constant string
|
||||
not call.getPathArgument().getALocalSource().asExpr().getExpr().(StringLiteral).getComponent(0)
|
||||
instanceof StringTextComponent
|
||||
select call,
|
||||
"Call to " + call.getName() + " with a non-constant value. Consider replacing it with " +
|
||||
call.getReplacement() + "."
|
||||
43
ruby/ql/src/queries/security/cwe-598/SensitiveGetQuery.qhelp
Normal file
43
ruby/ql/src/queries/security/cwe-598/SensitiveGetQuery.qhelp
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Sensitive information such as passwords should not be transmitted within the query string of the requested URL.
|
||||
Sensitive information within URLs may be logged in various locations, including the user's browser, the web server,
|
||||
and any proxy servers between the two endpoints. URLs may also be displayed on-screen, bookmarked
|
||||
or emailed around by users. They may be disclosed to third parties via the Referer header when any off-site links are
|
||||
followed. Placing sensitive information into the URL therefore increases the risk that it will be captured by an attacker.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Use HTTP POST to send sensitive information as part of the request body; for example, as form data.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows two route handlers that both receive a username and a password.
|
||||
The first receives this sensitive information from the query parameters of a GET request, which is
|
||||
transmitted in the URL. The second receives this sensitive information from the request body of a POST request.
|
||||
</p>
|
||||
<sample src="examples/routes.rb" />
|
||||
<sample src="examples/users_controller.rb" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
CWE:
|
||||
<a href="https://cwe.mitre.org/data/definitions/598.html">CWE-598: Use of GET Request Method with Sensitive Query Strings</a>
|
||||
</li>
|
||||
<li>
|
||||
PortSwigger (Burp):
|
||||
<a href="https://portswigger.net/kb/issues/00400300_password-submitted-using-get-method">Password Submitted using GET Method</a>
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://owasp.org/www-community/vulnerabilities/Information_exposure_through_query_strings_in_url">Information Exposure through Query Strings in URL</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
23
ruby/ql/src/queries/security/cwe-598/SensitiveGetQuery.ql
Normal file
23
ruby/ql/src/queries/security/cwe-598/SensitiveGetQuery.ql
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @name Sensitive data read from GET request
|
||||
* @description Placing sensitive data in a GET request increases the risk of
|
||||
* the data being exposed to an attacker.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.5
|
||||
* @precision high
|
||||
* @id rb/sensitive-get-query
|
||||
* @tags security
|
||||
* external/cwe/cwe-598
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import DataFlow::PathGraph
|
||||
import codeql.ruby.security.SensitiveGetQueryQuery
|
||||
import codeql.ruby.security.SensitiveActions
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveGetQuery::Configuration config
|
||||
where config.hasFlowPath(source, sink)
|
||||
select source.getNode(), source, sink,
|
||||
"$@ for GET requests uses query parameter as sensitive data.",
|
||||
source.getNode().(SensitiveGetQuery::Source).getHandler(), "Route handler"
|
||||
4
ruby/ql/src/queries/security/cwe-598/examples/routes.rb
Normal file
4
ruby/ql/src/queries/security/cwe-598/examples/routes.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Rails.application.routes.draw do
|
||||
get "users/login", to: "#login_get" # BAD: sensitive data transmitted through query parameters
|
||||
post "users/login", to: "users#login_post" # GOOD: sensitive data transmitted in the request body
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
class UsersController < ActionController::Base
|
||||
def login_get
|
||||
password = params[:password]
|
||||
authenticate_user(params[:username], password)
|
||||
end
|
||||
|
||||
def login_post
|
||||
password = params[:password]
|
||||
authenticate_user(params[:username], password)
|
||||
end
|
||||
|
||||
private
|
||||
def authenticate_user(username, password)
|
||||
# ... authenticate the user here
|
||||
end
|
||||
end
|
||||
@@ -3696,7 +3696,7 @@ cfg.rb:
|
||||
#-----| -> exit filter_nil
|
||||
|
||||
# 207| filter_nil
|
||||
#-----| -> exit cfg.rb (normal)
|
||||
#-----| -> self
|
||||
|
||||
# 207| list
|
||||
#-----| -> list
|
||||
@@ -3733,6 +3733,35 @@ cfg.rb:
|
||||
# 209| call to nil?
|
||||
#-----| -> exit do ... end (normal)
|
||||
|
||||
# 213| call to do_something
|
||||
#-----| -> exit cfg.rb (normal)
|
||||
|
||||
# 213| self
|
||||
#-----| -> do ... end
|
||||
|
||||
# 213| do ... end
|
||||
#-----| -> call to do_something
|
||||
|
||||
# 213| enter do ... end
|
||||
#-----| -> self
|
||||
|
||||
# 213| exit do ... end
|
||||
|
||||
# 213| exit do ... end (normal)
|
||||
#-----| -> exit do ... end
|
||||
|
||||
# 214| self
|
||||
#-----| -> call to something
|
||||
|
||||
# 214| call to something
|
||||
#-----| -> self
|
||||
|
||||
# 215| call to something_else
|
||||
#-----| -> exit do ... end (normal)
|
||||
|
||||
# 215| self
|
||||
#-----| -> call to something_else
|
||||
|
||||
desugar.rb:
|
||||
# 1| enter m1
|
||||
#-----| -> x
|
||||
|
||||
@@ -44,6 +44,9 @@ callsWithNoArguments
|
||||
| cfg.rb:205:1:205:3 | call to foo |
|
||||
| cfg.rb:208:3:210:5 | call to reject |
|
||||
| cfg.rb:209:5:209:13 | call to nil? |
|
||||
| cfg.rb:213:1:216:3 | call to do_something |
|
||||
| cfg.rb:214:3:214:16 | call to something |
|
||||
| cfg.rb:215:3:215:16 | call to something_else |
|
||||
| desugar.rb:6:3:6:7 | call to foo |
|
||||
| desugar.rb:10:3:10:7 | call to foo |
|
||||
| desugar.rb:14:3:14:7 | call to foo |
|
||||
|
||||
@@ -210,6 +210,11 @@ def filter_nil list
|
||||
end
|
||||
end
|
||||
|
||||
do_something do
|
||||
self.something
|
||||
something_else
|
||||
end
|
||||
|
||||
__END__
|
||||
|
||||
Some ignored nonsense
|
||||
|
||||
@@ -85,7 +85,7 @@ else
|
||||
foo
|
||||
end
|
||||
|
||||
if foos.index(foo)r == nil
|
||||
if foos.index(foo) == nil
|
||||
foo
|
||||
else
|
||||
foo
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
actionControllerControllerClasses
|
||||
| action_controller/input_access.rb:1:1:50:3 | UsersController |
|
||||
| action_controller/params_flow.rb:1:1:151:3 | MyController |
|
||||
| active_record/ActiveRecord.rb:23:1:39:3 | FooController |
|
||||
| active_record/ActiveRecord.rb:41:1:64:3 | BarController |
|
||||
| active_record/ActiveRecord.rb:66:1:98:3 | BazController |
|
||||
| active_record/ActiveRecord.rb:100:1:108:3 | AnnotatedController |
|
||||
| active_storage/active_storage.rb:39:1:45:3 | PostsController |
|
||||
| app/controllers/comments_controller.rb:1:1:7:3 | CommentsController |
|
||||
| app/controllers/comments_controller.rb:1:1:40:3 | CommentsController |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:46:3 | BarsController |
|
||||
| app/controllers/photos_controller.rb:1:1:4:3 | PhotosController |
|
||||
| app/controllers/posts_controller.rb:1:1:10:3 | PostsController |
|
||||
| app/controllers/tags_controller.rb:1:1:2:3 | TagsController |
|
||||
| app/controllers/users/notifications_controller.rb:2:3:5:5 | NotificationsController |
|
||||
actionControllerActionMethods
|
||||
| action_controller/input_access.rb:2:3:49:5 | index |
|
||||
| action_controller/params_flow.rb:2:3:4:5 | m1 |
|
||||
| action_controller/params_flow.rb:6:3:8:5 | m2 |
|
||||
| action_controller/params_flow.rb:10:3:12:5 | m2 |
|
||||
@@ -59,8 +61,8 @@ actionControllerActionMethods
|
||||
| active_record/ActiveRecord.rb:101:3:103:5 | index |
|
||||
| active_record/ActiveRecord.rb:105:3:107:5 | unsafe_action |
|
||||
| active_storage/active_storage.rb:40:3:44:5 | create |
|
||||
| app/controllers/comments_controller.rb:2:3:3:5 | index |
|
||||
| app/controllers/comments_controller.rb:5:3:6:5 | show |
|
||||
| app/controllers/comments_controller.rb:2:3:36:5 | index |
|
||||
| app/controllers/comments_controller.rb:38:3:39:5 | show |
|
||||
| app/controllers/foo/bars_controller.rb:5:3:7:5 | index |
|
||||
| app/controllers/foo/bars_controller.rb:9:3:18:5 | show_debug |
|
||||
| app/controllers/foo/bars_controller.rb:20:3:24:5 | show |
|
||||
@@ -222,6 +224,137 @@ paramsSources
|
||||
| app/controllers/foo/bars_controller.rb:21:21:21:26 | call to params |
|
||||
| app/controllers/foo/bars_controller.rb:22:10:22:15 | call to params |
|
||||
| app/views/foo/bars/show.html.erb:5:9:5:14 | call to params |
|
||||
httpInputAccesses
|
||||
| action_controller/input_access.rb:3:5:3:18 | call to params | ActionDispatch::Request#params |
|
||||
| action_controller/input_access.rb:4:5:4:22 | call to parameters | ActionDispatch::Request#parameters |
|
||||
| action_controller/input_access.rb:5:5:5:15 | call to GET | ActionDispatch::Request#GET |
|
||||
| action_controller/input_access.rb:6:5:6:16 | call to POST | ActionDispatch::Request#POST |
|
||||
| action_controller/input_access.rb:7:5:7:28 | call to query_parameters | ActionDispatch::Request#query_parameters |
|
||||
| action_controller/input_access.rb:8:5:8:30 | call to request_parameters | ActionDispatch::Request#request_parameters |
|
||||
| action_controller/input_access.rb:9:5:9:31 | call to filtered_parameters | ActionDispatch::Request#filtered_parameters |
|
||||
| action_controller/input_access.rb:11:5:11:25 | call to authorization | ActionDispatch::Request#authorization |
|
||||
| action_controller/input_access.rb:12:5:12:23 | call to script_name | ActionDispatch::Request#script_name |
|
||||
| action_controller/input_access.rb:13:5:13:21 | call to path_info | ActionDispatch::Request#path_info |
|
||||
| action_controller/input_access.rb:14:5:14:22 | call to user_agent | ActionDispatch::Request#user_agent |
|
||||
| action_controller/input_access.rb:15:5:15:19 | call to referer | ActionDispatch::Request#referer |
|
||||
| action_controller/input_access.rb:16:5:16:20 | call to referrer | ActionDispatch::Request#referrer |
|
||||
| action_controller/input_access.rb:17:5:17:26 | call to host_authority | ActionDispatch::Request#host_authority |
|
||||
| action_controller/input_access.rb:18:5:18:24 | call to content_type | ActionDispatch::Request#content_type |
|
||||
| action_controller/input_access.rb:19:5:19:16 | call to host | ActionDispatch::Request#host |
|
||||
| action_controller/input_access.rb:20:5:20:20 | call to hostname | ActionDispatch::Request#hostname |
|
||||
| action_controller/input_access.rb:21:5:21:27 | call to accept_encoding | ActionDispatch::Request#accept_encoding |
|
||||
| action_controller/input_access.rb:22:5:22:27 | call to accept_language | ActionDispatch::Request#accept_language |
|
||||
| action_controller/input_access.rb:23:5:23:25 | call to if_none_match | ActionDispatch::Request#if_none_match |
|
||||
| action_controller/input_access.rb:24:5:24:31 | call to if_none_match_etags | ActionDispatch::Request#if_none_match_etags |
|
||||
| action_controller/input_access.rb:25:5:25:29 | call to content_mime_type | ActionDispatch::Request#content_mime_type |
|
||||
| action_controller/input_access.rb:27:5:27:21 | call to authority | ActionDispatch::Request#authority |
|
||||
| action_controller/input_access.rb:28:5:28:16 | call to host | ActionDispatch::Request#host |
|
||||
| action_controller/input_access.rb:29:5:29:26 | call to host_authority | ActionDispatch::Request#host_authority |
|
||||
| action_controller/input_access.rb:30:5:30:26 | call to host_with_port | ActionDispatch::Request#host_with_port |
|
||||
| action_controller/input_access.rb:31:5:31:20 | call to hostname | ActionDispatch::Request#hostname |
|
||||
| action_controller/input_access.rb:32:5:32:25 | call to forwarded_for | ActionDispatch::Request#forwarded_for |
|
||||
| action_controller/input_access.rb:33:5:33:26 | call to forwarded_host | ActionDispatch::Request#forwarded_host |
|
||||
| action_controller/input_access.rb:34:5:34:16 | call to port | ActionDispatch::Request#port |
|
||||
| action_controller/input_access.rb:35:5:35:26 | call to forwarded_port | ActionDispatch::Request#forwarded_port |
|
||||
| action_controller/input_access.rb:37:5:37:22 | call to media_type | ActionDispatch::Request#media_type |
|
||||
| action_controller/input_access.rb:38:5:38:29 | call to media_type_params | ActionDispatch::Request#media_type_params |
|
||||
| action_controller/input_access.rb:39:5:39:27 | call to content_charset | ActionDispatch::Request#content_charset |
|
||||
| action_controller/input_access.rb:40:5:40:20 | call to base_url | ActionDispatch::Request#base_url |
|
||||
| action_controller/input_access.rb:42:5:42:16 | call to body | ActionDispatch::Request#body |
|
||||
| action_controller/input_access.rb:43:5:43:20 | call to raw_post | ActionDispatch::Request#raw_post |
|
||||
| action_controller/input_access.rb:45:5:45:30 | ...[...] | ActionDispatch::Request#env[] |
|
||||
| action_controller/input_access.rb:47:5:47:39 | ...[...] | ActionDispatch::Request#env[] |
|
||||
| action_controller/params_flow.rb:3:10:3:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:7:10:7:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:11:10:11:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:15:10:15:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:19:10:19:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:23:10:23:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:27:10:27:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:31:10:31:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:35:10:35:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:39:10:39:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:43:10:43:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:47:10:47:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:51:10:51:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:55:10:55:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:59:10:59:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:63:10:63:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:67:10:67:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:71:10:71:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:75:10:75:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:79:10:79:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:83:10:83:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:87:10:87:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:91:10:91:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:95:10:95:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:99:10:99:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:103:10:103:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:107:10:107:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:111:10:111:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:112:23:112:28 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:116:10:116:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:117:31:117:36 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:121:10:121:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:122:31:122:36 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:126:10:126:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:127:24:127:29 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:130:14:130:19 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:135:10:135:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:136:32:136:37 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:139:22:139:27 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:144:10:144:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:145:32:145:37 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:148:22:148:27 | call to params | ActionController::Metal#params |
|
||||
| action_mailer/mailer.rb:3:10:3:15 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:28:30:28:35 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:29:29:29:34 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:30:31:30:36 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:32:21:32:26 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:34:34:34:39 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:35:23:35:28 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:35:38:35:43 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:43:10:43:15 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:50:11:50:16 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:54:12:54:17 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:59:12:59:17 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:62:15:62:20 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:68:21:68:26 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:72:18:72:23 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:76:24:76:29 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:76:49:76:54 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:80:25:80:30 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:80:50:80:55 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:88:21:88:26 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:92:27:92:32 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:92:52:92:57 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:96:28:96:33 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:96:53:96:58 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:106:59:106:64 | call to params | ActionController::Metal#params |
|
||||
| active_storage/active_storage.rb:41:21:41:26 | call to params | ActionController::Metal#params |
|
||||
| active_storage/active_storage.rb:42:24:42:29 | call to params | ActionController::Metal#params |
|
||||
| app/controllers/comments_controller.rb:3:5:3:18 | call to params | ActionDispatch::Request#params |
|
||||
| app/controllers/comments_controller.rb:4:5:4:22 | call to parameters | ActionDispatch::Request#parameters |
|
||||
| app/controllers/comments_controller.rb:5:5:5:15 | call to GET | ActionDispatch::Request#GET |
|
||||
| app/controllers/comments_controller.rb:6:5:6:16 | call to POST | ActionDispatch::Request#POST |
|
||||
| app/controllers/comments_controller.rb:7:5:7:28 | call to query_parameters | ActionDispatch::Request#query_parameters |
|
||||
| app/controllers/comments_controller.rb:8:5:8:30 | call to request_parameters | ActionDispatch::Request#request_parameters |
|
||||
| app/controllers/comments_controller.rb:9:5:9:31 | call to filtered_parameters | ActionDispatch::Request#filtered_parameters |
|
||||
| app/controllers/foo/bars_controller.rb:10:27:10:33 | call to cookies | ActionController::Metal#cookies |
|
||||
| app/controllers/foo/bars_controller.rb:13:21:13:26 | call to params | ActionController::Metal#params |
|
||||
| app/controllers/foo/bars_controller.rb:14:10:14:15 | call to params | ActionController::Metal#params |
|
||||
| app/controllers/foo/bars_controller.rb:21:21:21:26 | call to params | ActionController::Metal#params |
|
||||
| app/controllers/foo/bars_controller.rb:22:10:22:15 | call to params | ActionController::Metal#params |
|
||||
| app/graphql/mutations/dummy.rb:5:24:5:25 | id | GraphQL RoutedParameter |
|
||||
| app/graphql/mutations/dummy.rb:9:17:9:25 | something | GraphQL RoutedParameter |
|
||||
| app/graphql/resolvers/dummy_resolver.rb:6:24:6:25 | id | GraphQL RoutedParameter |
|
||||
| app/graphql/resolvers/dummy_resolver.rb:10:17:10:25 | something | GraphQL RoutedParameter |
|
||||
| app/graphql/types/query_type.rb:10:18:10:23 | number | GraphQL RoutedParameter |
|
||||
| app/graphql/types/query_type.rb:18:23:18:33 | blah_number | GraphQL RoutedParameter |
|
||||
| app/graphql/types/query_type.rb:27:20:27:25 | **args | GraphQL RoutedParameter |
|
||||
| app/graphql/types/query_type.rb:36:34:36:37 | arg1 | GraphQL RoutedParameter |
|
||||
| app/graphql/types/query_type.rb:36:41:36:46 | **rest | GraphQL RoutedParameter |
|
||||
| app/views/foo/bars/show.html.erb:5:9:5:14 | call to params | ActionController::Metal#params |
|
||||
cookiesCalls
|
||||
| app/controllers/foo/bars_controller.rb:10:27:10:33 | call to cookies |
|
||||
cookiesSources
|
||||
@@ -237,3 +370,19 @@ getAssociatedControllerClasses
|
||||
controllerTemplateFiles
|
||||
| app/controllers/foo/bars_controller.rb:3:1:46:3 | BarsController | app/views/foo/bars/_widget.html.erb:0:0:0:0 | app/views/foo/bars/_widget.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:46:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
|
||||
headerWriteAccesses
|
||||
| app/controllers/comments_controller.rb:15:5:15:35 | call to []= | content-type | app/controllers/comments_controller.rb:15:39:15:49 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:16:5:16:46 | call to set_header | content-length | app/controllers/comments_controller.rb:16:43:16:45 | 100 |
|
||||
| app/controllers/comments_controller.rb:17:5:17:39 | call to []= | x-custom-header | app/controllers/comments_controller.rb:17:43:17:46 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:18:5:18:39 | call to []= | x-another-custom-header | app/controllers/comments_controller.rb:18:43:18:47 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:19:5:19:49 | call to add_header | x-yet-another | app/controllers/comments_controller.rb:19:42:19:49 | "indeed" |
|
||||
| app/controllers/comments_controller.rb:25:5:25:21 | call to location= | location | app/controllers/comments_controller.rb:25:25:25:36 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:26:5:26:26 | call to cache_control= | cache-control | app/controllers/comments_controller.rb:26:30:26:36 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:27:5:27:27 | call to _cache_control= | cache-control | app/controllers/comments_controller.rb:27:31:27:37 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:28:5:28:17 | call to etag= | etag | app/controllers/comments_controller.rb:28:21:28:27 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:29:5:29:20 | call to charset= | content-type | app/controllers/comments_controller.rb:29:24:29:30 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:30:5:30:25 | call to content_type= | content-type | app/controllers/comments_controller.rb:30:29:30:35 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:32:5:32:17 | call to date= | date | app/controllers/comments_controller.rb:32:21:32:30 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:33:5:33:26 | call to last_modified= | last-modified | app/controllers/comments_controller.rb:33:30:33:43 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:34:5:34:22 | call to weak_etag= | etag | app/controllers/comments_controller.rb:34:26:34:32 | ... = ... |
|
||||
| app/controllers/comments_controller.rb:35:5:35:24 | call to strong_etag= | etag | app/controllers/comments_controller.rb:35:28:35:34 | ... = ... |
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.frameworks.ActionController
|
||||
private import codeql.ruby.frameworks.Rails
|
||||
private import codeql.ruby.frameworks.ActionView
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
|
||||
query predicate actionControllerControllerClasses(ActionControllerControllerClass cls) { any() }
|
||||
|
||||
@@ -10,6 +13,10 @@ query predicate paramsCalls(Rails::ParamsCall c) { any() }
|
||||
|
||||
query predicate paramsSources(ParamsSource src) { any() }
|
||||
|
||||
query predicate httpInputAccesses(Http::Server::RequestInputAccess a, string sourceType) {
|
||||
sourceType = a.getSourceType()
|
||||
}
|
||||
|
||||
query predicate cookiesCalls(Rails::CookiesCall c) { any() }
|
||||
|
||||
query predicate cookiesSources(CookiesSource src) { any() }
|
||||
@@ -25,3 +32,9 @@ query predicate getAssociatedControllerClasses(ActionControllerControllerClass c
|
||||
query predicate controllerTemplateFiles(ActionControllerControllerClass cls, ErbFile templateFile) {
|
||||
controllerTemplateFile(cls, templateFile)
|
||||
}
|
||||
|
||||
query predicate headerWriteAccesses(
|
||||
Http::Server::HeaderWriteAccess a, string name, DataFlow::Node value
|
||||
) {
|
||||
name = a.getName() and value = a.getValue()
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ actionDispatchRoutes
|
||||
actionDispatchControllerMethods
|
||||
| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index |
|
||||
| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show |
|
||||
| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:3:5 | index |
|
||||
| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:5:3:6:5 | show |
|
||||
| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index |
|
||||
| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show |
|
||||
| app/config/routes.rb:7:5:7:37 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote |
|
||||
| app/config/routes.rb:27:3:27:48 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show |
|
||||
| app/config/routes.rb:28:3:28:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show |
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
htmlSafeCalls
|
||||
| app/views/foo/bars/show.html.erb:23:3:23:25 | call to html_safe |
|
||||
| app/views/foo/bars/show.html.erb:27:3:27:25 | call to html_safe |
|
||||
rawCalls
|
||||
| app/views/foo/bars/_widget.html.erb:1:5:1:21 | call to raw |
|
||||
| app/views/foo/bars/_widget.html.erb:2:5:2:20 | call to raw |
|
||||
@@ -24,6 +21,8 @@ renderToCalls
|
||||
linkToCalls
|
||||
| app/views/foo/bars/show.html.erb:33:5:33:41 | call to link_to |
|
||||
httpResponses
|
||||
| app/controllers/comments_controller.rb:11:5:11:17 | call to body= | app/controllers/comments_controller.rb:11:21:11:34 | ... = ... | text/http |
|
||||
| app/controllers/comments_controller.rb:21:5:21:37 | call to send_file | app/controllers/comments_controller.rb:21:24:21:36 | "my-file.ext" | application/octet-stream |
|
||||
| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | app/controllers/foo/bars_controller.rb:15:33:15:47 | "foo/bars/show" | text/html |
|
||||
| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | app/controllers/foo/bars_controller.rb:23:12:23:26 | "foo/bars/show" | text/html |
|
||||
| app/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | app/controllers/foo/bars_controller.rb:35:18:35:33 | call to [] | application/json |
|
||||
|
||||
@@ -4,8 +4,6 @@ private import codeql.ruby.frameworks.ActionView
|
||||
private import codeql.ruby.frameworks.Rails
|
||||
private import codeql.ruby.Concepts
|
||||
|
||||
query predicate htmlSafeCalls(Rails::HtmlSafeCall c) { any() }
|
||||
|
||||
query predicate rawCalls(RawCall c) { any() }
|
||||
|
||||
query predicate renderCalls(Rails::RenderCall c) { any() }
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
class UsersController < ActionController::Base
|
||||
def index
|
||||
request.params
|
||||
request.parameters
|
||||
request.GET
|
||||
request.POST
|
||||
request.query_parameters
|
||||
request.request_parameters
|
||||
request.filtered_parameters
|
||||
|
||||
request.authorization
|
||||
request.script_name
|
||||
request.path_info
|
||||
request.user_agent
|
||||
request.referer
|
||||
request.referrer
|
||||
request.host_authority
|
||||
request.content_type
|
||||
request.host
|
||||
request.hostname
|
||||
request.accept_encoding
|
||||
request.accept_language
|
||||
request.if_none_match
|
||||
request.if_none_match_etags
|
||||
request.content_mime_type
|
||||
|
||||
request.authority
|
||||
request.host
|
||||
request.host_authority
|
||||
request.host_with_port
|
||||
request.hostname
|
||||
request.forwarded_for
|
||||
request.forwarded_host
|
||||
request.port
|
||||
request.forwarded_port
|
||||
|
||||
request.media_type
|
||||
request.media_type_params
|
||||
request.content_charset
|
||||
request.base_url
|
||||
|
||||
request.body
|
||||
request.raw_post
|
||||
|
||||
request.env["HTTP_ACCEPT"]
|
||||
request.env["NOT_USER_CONTROLLED"]
|
||||
request.filtered_env["HTTP_ACCEPT"]
|
||||
request.filtered_env["NOT_USER_CONTROLLED"]
|
||||
end
|
||||
end
|
||||
@@ -136,6 +136,14 @@ edges
|
||||
| active_support.rb:191:34:191:34 | a : | active_support.rb:191:7:191:35 | call to new : |
|
||||
| active_support.rb:192:7:192:7 | x : | active_support.rb:192:7:192:16 | call to to_param : |
|
||||
| active_support.rb:192:7:192:16 | call to to_param : | active_support.rb:193:8:193:8 | y |
|
||||
| active_support.rb:197:7:197:16 | call to source : | active_support.rb:198:20:198:20 | a : |
|
||||
| active_support.rb:198:7:198:21 | call to new : | active_support.rb:199:7:199:7 | x : |
|
||||
| active_support.rb:198:20:198:20 | a : | active_support.rb:198:7:198:21 | call to new : |
|
||||
| active_support.rb:199:7:199:7 | x : | active_support.rb:199:7:199:17 | call to existence : |
|
||||
| active_support.rb:199:7:199:17 | call to existence : | active_support.rb:200:8:200:8 | y |
|
||||
| active_support.rb:199:7:199:17 | call to existence : | active_support.rb:201:7:201:7 | y : |
|
||||
| active_support.rb:201:7:201:7 | y : | active_support.rb:201:7:201:17 | call to existence : |
|
||||
| active_support.rb:201:7:201:17 | call to existence : | active_support.rb:202:8:202:8 | z |
|
||||
nodes
|
||||
| active_support.rb:9:9:9:18 | call to source : | semmle.label | call to source : |
|
||||
| active_support.rb:10:10:10:10 | x : | semmle.label | x : |
|
||||
@@ -310,6 +318,15 @@ nodes
|
||||
| active_support.rb:192:7:192:7 | x : | semmle.label | x : |
|
||||
| active_support.rb:192:7:192:16 | call to to_param : | semmle.label | call to to_param : |
|
||||
| active_support.rb:193:8:193:8 | y | semmle.label | y |
|
||||
| active_support.rb:197:7:197:16 | call to source : | semmle.label | call to source : |
|
||||
| active_support.rb:198:7:198:21 | call to new : | semmle.label | call to new : |
|
||||
| active_support.rb:198:20:198:20 | a : | semmle.label | a : |
|
||||
| active_support.rb:199:7:199:7 | x : | semmle.label | x : |
|
||||
| active_support.rb:199:7:199:17 | call to existence : | semmle.label | call to existence : |
|
||||
| active_support.rb:200:8:200:8 | y | semmle.label | y |
|
||||
| active_support.rb:201:7:201:7 | y : | semmle.label | y : |
|
||||
| active_support.rb:201:7:201:17 | call to existence : | semmle.label | call to existence : |
|
||||
| active_support.rb:202:8:202:8 | z | semmle.label | z |
|
||||
subpaths
|
||||
#select
|
||||
| active_support.rb:106:10:106:13 | ...[...] | active_support.rb:104:10:104:17 | call to source : | active_support.rb:106:10:106:13 | ...[...] | $@ | active_support.rb:104:10:104:17 | call to source : | call to source : |
|
||||
|
||||
@@ -192,3 +192,12 @@ def m_safe_buffer_to_param
|
||||
y = x.to_param
|
||||
sink y # $hasTaintFlow=a
|
||||
end
|
||||
|
||||
def m_pathname_existence
|
||||
a = source "a"
|
||||
x = Pathname.new(a)
|
||||
y = x.existence
|
||||
sink y # $hasTaintFlow=a
|
||||
z = y.existence
|
||||
sink z # $hasTaintFlow=a
|
||||
end
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
class CommentsController < ApplicationController
|
||||
def index
|
||||
request.params
|
||||
request.parameters
|
||||
request.GET
|
||||
request.POST
|
||||
request.query_parameters
|
||||
request.request_parameters
|
||||
request.filtered_parameters
|
||||
|
||||
response.body = "some content"
|
||||
|
||||
response.status = 200
|
||||
|
||||
response.header["Content-Type"] = "text/html"
|
||||
response.set_header("Content-Length", 100)
|
||||
response.headers["X-Custom-Header"] = "hi"
|
||||
response["X-Another-Custom-Header"] = "yes"
|
||||
response.add_header "X-Yet-Another", "indeed"
|
||||
|
||||
response.send_file("my-file.ext")
|
||||
|
||||
response.request
|
||||
|
||||
response.location = "http://..." # relevant for url redirect query
|
||||
response.cache_control = "value"
|
||||
response._cache_control = "value"
|
||||
response.etag = "value"
|
||||
response.charset = "value" # sets the charset part of the content-type header
|
||||
response.content_type = "value" # sets the main part of the content-type header
|
||||
|
||||
response.date = Date.today
|
||||
response.last_modified = Date.yesterday
|
||||
response.weak_etag = "value"
|
||||
response.strong_etag = "value"
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,27 +89,45 @@ calls.rb:
|
||||
# 377| SingletonOverride1
|
||||
#-----| super -> Object
|
||||
|
||||
# 404| SingletonOverride2
|
||||
# 412| SingletonOverride2
|
||||
#-----| super -> SingletonOverride1
|
||||
|
||||
# 421| ConditionalInstanceMethods
|
||||
# 433| ConditionalInstanceMethods
|
||||
#-----| super -> Object
|
||||
|
||||
# 484| ExtendSingletonMethod
|
||||
# 496| ExtendSingletonMethod
|
||||
|
||||
# 494| ExtendSingletonMethod2
|
||||
# 506| ExtendSingletonMethod2
|
||||
|
||||
# 500| ExtendSingletonMethod3
|
||||
# 512| ExtendSingletonMethod3
|
||||
|
||||
# 513| ProtectedMethodInModule
|
||||
# 525| ProtectedMethodInModule
|
||||
|
||||
# 519| ProtectedMethods
|
||||
# 531| ProtectedMethods
|
||||
#-----| super -> Object
|
||||
#-----| include -> ProtectedMethodInModule
|
||||
|
||||
# 538| ProtectedMethodsSub
|
||||
# 550| ProtectedMethodsSub
|
||||
#-----| super -> ProtectedMethods
|
||||
|
||||
# 564| SingletonUpCall_Base
|
||||
#-----| super -> Object
|
||||
|
||||
# 568| SingletonUpCall_Sub
|
||||
#-----| super -> SingletonUpCall_Base
|
||||
|
||||
# 576| SingletonUpCall_SubSub
|
||||
#-----| super -> SingletonUpCall_Sub
|
||||
|
||||
# 583| SingletonA
|
||||
#-----| super -> Object
|
||||
|
||||
# 596| SingletonB
|
||||
#-----| super -> SingletonA
|
||||
|
||||
# 605| SingletonC
|
||||
#-----| super -> SingletonA
|
||||
|
||||
hello.rb:
|
||||
# 1| EnglishWords
|
||||
|
||||
@@ -204,9 +222,6 @@ modules_rec.rb:
|
||||
# 1| B::A
|
||||
#-----| super -> Object
|
||||
|
||||
# 4| A::B
|
||||
#-----| super -> Object
|
||||
|
||||
private.rb:
|
||||
# 1| E
|
||||
#-----| super -> Object
|
||||
@@ -218,3 +233,9 @@ private.rb:
|
||||
|
||||
# 96| PrivateOverride2
|
||||
#-----| super -> PrivateOverride1
|
||||
|
||||
toplevel_self_singleton.rb:
|
||||
# 2| A::B
|
||||
#-----| super -> Object
|
||||
|
||||
# 24| Good
|
||||
|
||||
@@ -8,7 +8,6 @@ getTarget
|
||||
| calls.rb:17:1:17:8 | call to bar | calls.rb:13:1:15:3 | bar |
|
||||
| calls.rb:19:1:19:8 | call to foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:19:1:19:8 | call to foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:23:9:23:19 | call to singleton_m | calls.rb:25:5:27:7 | singleton_m |
|
||||
| calls.rb:32:5:32:15 | call to singleton_m | calls.rb:25:5:27:7 | singleton_m |
|
||||
| calls.rb:33:5:33:20 | call to singleton_m | calls.rb:25:5:27:7 | singleton_m |
|
||||
| calls.rb:37:1:37:13 | call to singleton_m | calls.rb:25:5:27:7 | singleton_m |
|
||||
@@ -77,7 +76,6 @@ getTarget
|
||||
| calls.rb:224:9:224:24 | call to singleton_g | calls.rb:236:1:238:3 | singleton_g |
|
||||
| calls.rb:224:9:224:24 | call to singleton_g | calls.rb:243:1:245:3 | singleton_g |
|
||||
| calls.rb:224:9:224:24 | call to singleton_g | calls.rb:251:5:253:7 | singleton_g |
|
||||
| calls.rb:224:9:224:24 | call to singleton_g | calls.rb:267:1:269:3 | singleton_g |
|
||||
| calls.rb:228:1:228:22 | call to singleton_a | calls.rb:191:5:194:7 | singleton_a |
|
||||
| calls.rb:229:1:229:22 | call to singleton_f | calls.rb:218:9:220:11 | singleton_f |
|
||||
| calls.rb:231:6:231:19 | call to new | calls.rb:117:5:117:16 | new |
|
||||
@@ -148,73 +146,93 @@ getTarget
|
||||
| calls.rb:375:1:375:11 | call to instance | calls.rb:368:5:370:7 | instance |
|
||||
| calls.rb:380:13:380:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:379:9:381:11 | singleton1 |
|
||||
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:389:9:389:44 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:393:9:393:18 | call to singleton2 | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:393:9:393:18 | call to singleton2 | calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:396:5:396:14 | call to singleton2 | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:399:1:399:29 | call to singleton1 | calls.rb:379:9:381:11 | singleton1 |
|
||||
| calls.rb:400:1:400:29 | call to singleton2 | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:401:1:401:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:402:1:402:34 | call to call_singleton2 | calls.rb:392:5:394:7 | call_singleton2 |
|
||||
| calls.rb:407:13:407:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:412:9:412:44 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:416:1:416:29 | call to singleton1 | calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:417:1:417:29 | call to singleton2 | calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:418:1:418:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:419:1:419:34 | call to call_singleton2 | calls.rb:392:5:394:7 | call_singleton2 |
|
||||
| calls.rb:424:13:424:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:429:9:429:44 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:432:13:432:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:435:17:435:52 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:443:9:447:11 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:443:9:447:15 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:445:17:445:40 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:451:1:451:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:451:1:451:33 | call to m1 | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:452:1:452:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:453:1:453:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:453:1:453:33 | call to m2 | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:454:1:454:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:455:1:455:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:456:1:456:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:458:27:476:3 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:461:13:461:22 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:465:5:469:7 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:465:5:469:11 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:467:13:467:22 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:473:13:473:27 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:478:1:478:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:479:1:479:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:480:1:480:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:481:1:481:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:482:1:482:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:492:1:492:31 | call to singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:498:1:498:32 | call to singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:505:1:505:32 | call to singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:511:1:511:13 | call to singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:520:5:520:35 | call to include | calls.rb:108:5:110:7 | include |
|
||||
| calls.rb:523:9:523:35 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:527:9:527:11 | call to foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:528:9:528:11 | call to bar | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:529:9:529:28 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:529:9:529:32 | call to foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:530:9:530:28 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:530:9:530:32 | call to bar | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:534:1:534:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:535:1:535:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:536:1:536:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:536:1:536:24 | call to baz | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:540:9:540:11 | call to foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:541:9:541:31 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:541:9:541:35 | call to foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:545:1:545:23 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:546:1:546:23 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:547:1:547:23 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:547:1:547:27 | call to baz | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:549:2:549:6 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:549:20:549:24 | call to baz | calls.rb:51:5:57:7 | baz |
|
||||
| calls.rb:550:26:550:37 | call to capitalize | calls.rb:97:5:97:23 | capitalize |
|
||||
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:388:13:388:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:388:13:388:30 | call to instance1 | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:388:13:388:30 | call to instance1 | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:393:9:393:44 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:397:9:397:18 | call to singleton2 | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:397:9:397:18 | call to singleton2 | calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:400:5:400:14 | call to singleton2 | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:403:9:403:43 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:407:1:407:29 | call to singleton1 | calls.rb:379:9:381:11 | singleton1 |
|
||||
| calls.rb:408:1:408:29 | call to singleton2 | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:409:1:409:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:410:1:410:34 | call to call_singleton2 | calls.rb:396:5:398:7 | call_singleton2 |
|
||||
| calls.rb:415:13:415:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:420:9:420:44 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:424:9:424:43 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:428:1:428:29 | call to singleton1 | calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:429:1:429:29 | call to singleton2 | calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:430:1:430:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:431:1:431:34 | call to call_singleton2 | calls.rb:396:5:398:7 | call_singleton2 |
|
||||
| calls.rb:436:13:436:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:441:9:441:44 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:444:13:444:48 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:447:17:447:52 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:455:9:459:11 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:455:9:459:15 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:457:17:457:40 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:463:1:463:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:463:1:463:33 | call to m1 | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:464:1:464:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:465:1:465:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:465:1:465:33 | call to m2 | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:466:1:466:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:467:1:467:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:468:1:468:30 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:470:27:488:3 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:473:13:473:22 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:477:5:481:7 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:477:5:481:11 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:479:13:479:22 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:485:13:485:27 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:490:1:490:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:491:1:491:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:492:1:492:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:493:1:493:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:494:1:494:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:504:1:504:31 | call to singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:510:1:510:32 | call to singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:517:1:517:32 | call to singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:523:1:523:13 | call to singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:532:5:532:35 | call to include | calls.rb:108:5:110:7 | include |
|
||||
| calls.rb:535:9:535:35 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:539:9:539:11 | call to foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:540:9:540:11 | call to bar | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:541:9:541:28 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:541:9:541:32 | call to foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:542:9:542:28 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:542:9:542:32 | call to bar | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:546:1:546:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:547:1:547:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:548:1:548:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:548:1:548:24 | call to baz | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:552:9:552:11 | call to foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:553:9:553:31 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:553:9:553:35 | call to foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:557:1:557:23 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:558:1:558:23 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:559:1:559:23 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:559:1:559:27 | call to baz | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:561:2:561:6 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:561:20:561:24 | call to baz | calls.rb:51:5:57:7 | baz |
|
||||
| calls.rb:562:26:562:37 | call to capitalize | calls.rb:97:5:97:23 | capitalize |
|
||||
| calls.rb:569:5:569:13 | call to singleton | calls.rb:565:5:566:7 | singleton |
|
||||
| calls.rb:572:9:572:17 | call to singleton | calls.rb:565:5:566:7 | singleton |
|
||||
| calls.rb:573:9:573:18 | call to singleton2 | calls.rb:577:5:578:7 | singleton2 |
|
||||
| calls.rb:580:5:580:14 | call to mid_method | calls.rb:571:5:574:7 | mid_method |
|
||||
| calls.rb:588:9:588:18 | call to singleton1 | calls.rb:584:5:585:7 | singleton1 |
|
||||
| calls.rb:588:9:588:18 | call to singleton1 | calls.rb:597:5:598:7 | singleton1 |
|
||||
| calls.rb:588:9:588:18 | call to singleton1 | calls.rb:606:5:607:7 | singleton1 |
|
||||
| calls.rb:592:9:592:23 | call to call_singleton1 | calls.rb:587:5:589:7 | call_singleton1 |
|
||||
| calls.rb:592:9:592:23 | call to call_singleton1 | calls.rb:600:5:602:7 | call_singleton1 |
|
||||
| calls.rb:592:9:592:23 | call to call_singleton1 | calls.rb:609:5:611:7 | call_singleton1 |
|
||||
| calls.rb:601:9:601:18 | call to singleton1 | calls.rb:597:5:598:7 | singleton1 |
|
||||
| calls.rb:610:9:610:18 | call to singleton1 | calls.rb:606:5:607:7 | singleton1 |
|
||||
| calls.rb:614:1:614:31 | call to call_call_singleton1 | calls.rb:591:5:593:7 | call_call_singleton1 |
|
||||
| calls.rb:615:1:615:31 | call to call_call_singleton1 | calls.rb:591:5:593:7 | call_call_singleton1 |
|
||||
| calls.rb:616:1:616:31 | call to call_call_singleton1 | calls.rb:591:5:593:7 | call_call_singleton1 |
|
||||
| hello.rb:12:5:12:24 | call to include | calls.rb:108:5:110:7 | include |
|
||||
| hello.rb:14:16:14:20 | call to hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:20:16:20:20 | call to super | hello.rb:13:5:15:7 | message |
|
||||
@@ -263,7 +281,10 @@ getTarget
|
||||
| private.rb:104:1:104:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| private.rb:104:1:104:28 | call to call_m1 | private.rb:91:3:93:5 | call_m1 |
|
||||
| private.rb:105:1:105:20 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| toplevel_self_singleton.rb:30:13:30:19 | call to call_me | toplevel_self_singleton.rb:26:9:27:11 | call_me |
|
||||
| toplevel_self_singleton.rb:31:13:31:20 | call to call_you | toplevel_self_singleton.rb:29:9:32:11 | call_you |
|
||||
unresolvedCall
|
||||
| calls.rb:23:9:23:19 | call to singleton_m |
|
||||
| calls.rb:26:9:26:18 | call to instance_m |
|
||||
| calls.rb:29:5:29:14 | call to instance_m |
|
||||
| calls.rb:30:5:30:19 | call to instance_m |
|
||||
@@ -296,44 +317,45 @@ unresolvedCall
|
||||
| calls.rb:274:1:274:14 | call to singleton_g |
|
||||
| calls.rb:276:1:276:14 | call to singleton_g |
|
||||
| calls.rb:313:9:313:20 | call to instance |
|
||||
| calls.rb:422:8:422:13 | call to rand |
|
||||
| calls.rb:422:8:422:17 | ... > ... |
|
||||
| calls.rb:439:9:439:10 | call to m3 |
|
||||
| calls.rb:442:8:442:13 | call to rand |
|
||||
| calls.rb:442:8:442:17 | ... > ... |
|
||||
| calls.rb:443:9:447:18 | call to m5 |
|
||||
| calls.rb:452:1:452:33 | call to m3 |
|
||||
| calls.rb:454:1:454:33 | call to m3 |
|
||||
| calls.rb:455:1:455:33 | call to m4 |
|
||||
| calls.rb:456:1:456:33 | call to m5 |
|
||||
| calls.rb:459:5:459:11 | call to [] |
|
||||
| calls.rb:459:5:463:7 | call to each |
|
||||
| calls.rb:465:5:469:15 | call to bar |
|
||||
| calls.rb:434:8:434:13 | call to rand |
|
||||
| calls.rb:434:8:434:17 | ... > ... |
|
||||
| calls.rb:451:9:451:10 | call to m3 |
|
||||
| calls.rb:454:8:454:13 | call to rand |
|
||||
| calls.rb:454:8:454:17 | ... > ... |
|
||||
| calls.rb:455:9:459:18 | call to m5 |
|
||||
| calls.rb:464:1:464:33 | call to m3 |
|
||||
| calls.rb:466:1:466:33 | call to m3 |
|
||||
| calls.rb:467:1:467:33 | call to m4 |
|
||||
| calls.rb:468:1:468:33 | call to m5 |
|
||||
| calls.rb:471:5:471:11 | call to [] |
|
||||
| calls.rb:471:5:475:7 | call to each |
|
||||
| calls.rb:472:9:474:11 | call to define_method |
|
||||
| calls.rb:478:1:478:31 | call to foo |
|
||||
| calls.rb:479:1:479:31 | call to bar |
|
||||
| calls.rb:480:1:480:33 | call to baz_0 |
|
||||
| calls.rb:481:1:481:33 | call to baz_1 |
|
||||
| calls.rb:482:1:482:33 | call to baz_2 |
|
||||
| calls.rb:486:9:486:46 | call to puts |
|
||||
| calls.rb:489:5:489:15 | call to extend |
|
||||
| calls.rb:495:5:495:32 | call to extend |
|
||||
| calls.rb:503:1:503:51 | call to extend |
|
||||
| calls.rb:508:1:508:13 | call to singleton |
|
||||
| calls.rb:509:1:509:32 | call to extend |
|
||||
| calls.rb:514:5:516:7 | call to protected |
|
||||
| calls.rb:515:9:515:42 | call to puts |
|
||||
| calls.rb:522:5:524:7 | call to protected |
|
||||
| calls.rb:534:1:534:24 | call to foo |
|
||||
| calls.rb:535:1:535:24 | call to bar |
|
||||
| calls.rb:545:1:545:27 | call to foo |
|
||||
| calls.rb:546:1:546:27 | call to bar |
|
||||
| calls.rb:549:1:549:7 | call to [] |
|
||||
| calls.rb:549:1:549:26 | call to each |
|
||||
| calls.rb:550:1:550:13 | call to [] |
|
||||
| calls.rb:550:1:550:39 | call to each |
|
||||
| calls.rb:477:5:481:15 | call to bar |
|
||||
| calls.rb:483:5:483:11 | call to [] |
|
||||
| calls.rb:483:5:487:7 | call to each |
|
||||
| calls.rb:484:9:486:11 | call to define_method |
|
||||
| calls.rb:490:1:490:31 | call to foo |
|
||||
| calls.rb:491:1:491:31 | call to bar |
|
||||
| calls.rb:492:1:492:33 | call to baz_0 |
|
||||
| calls.rb:493:1:493:33 | call to baz_1 |
|
||||
| calls.rb:494:1:494:33 | call to baz_2 |
|
||||
| calls.rb:498:9:498:46 | call to puts |
|
||||
| calls.rb:501:5:501:15 | call to extend |
|
||||
| calls.rb:507:5:507:32 | call to extend |
|
||||
| calls.rb:515:1:515:51 | call to extend |
|
||||
| calls.rb:520:1:520:13 | call to singleton |
|
||||
| calls.rb:521:1:521:32 | call to extend |
|
||||
| calls.rb:526:5:528:7 | call to protected |
|
||||
| calls.rb:527:9:527:42 | call to puts |
|
||||
| calls.rb:534:5:536:7 | call to protected |
|
||||
| calls.rb:546:1:546:24 | call to foo |
|
||||
| calls.rb:547:1:547:24 | call to bar |
|
||||
| calls.rb:557:1:557:27 | call to foo |
|
||||
| calls.rb:558:1:558:27 | call to bar |
|
||||
| calls.rb:561:1:561:7 | call to [] |
|
||||
| calls.rb:561:1:561:26 | call to each |
|
||||
| calls.rb:562:1:562:13 | call to [] |
|
||||
| calls.rb:562:1:562:39 | call to each |
|
||||
| calls.rb:570:5:570:14 | call to singleton2 |
|
||||
| hello.rb:20:16:20:26 | ... + ... |
|
||||
| hello.rb:20:16:20:34 | ... + ... |
|
||||
| hello.rb:20:16:20:40 | ... + ... |
|
||||
@@ -347,6 +369,11 @@ unresolvedCall
|
||||
| private.rb:57:1:57:14 | call to private4 |
|
||||
| private.rb:100:7:100:29 | call to m1 |
|
||||
| private.rb:105:1:105:23 | call to m1 |
|
||||
| toplevel_self_singleton.rb:8:1:16:3 | call to do_something |
|
||||
| toplevel_self_singleton.rb:10:9:10:27 | call to ab_singleton_method |
|
||||
| toplevel_self_singleton.rb:14:9:14:27 | call to ab_singleton_method |
|
||||
| toplevel_self_singleton.rb:18:12:22:1 | call to new |
|
||||
| toplevel_self_singleton.rb:20:9:20:27 | call to ab_singleton_method |
|
||||
privateMethod
|
||||
| calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:39:1:41:3 | call_instance_m |
|
||||
@@ -359,8 +386,8 @@ privateMethod
|
||||
| calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:460:9:462:11 | foo |
|
||||
| calls.rb:466:9:468:11 | bar |
|
||||
| calls.rb:472:9:474:11 | foo |
|
||||
| calls.rb:478:9:480:11 | bar |
|
||||
| private.rb:2:11:3:5 | private1 |
|
||||
| private.rb:8:3:9:5 | private2 |
|
||||
| private.rb:14:3:15:5 | private3 |
|
||||
@@ -377,6 +404,7 @@ privateMethod
|
||||
| private.rb:83:11:85:5 | m1 |
|
||||
| private.rb:87:11:89:5 | m2 |
|
||||
| private.rb:97:11:101:5 | m1 |
|
||||
| toplevel_self_singleton.rb:9:5:11:7 | method_in_block |
|
||||
publicMethod
|
||||
| calls.rb:7:1:9:3 | bar |
|
||||
| calls.rb:13:1:15:3 | bar |
|
||||
@@ -423,18 +451,31 @@ publicMethod
|
||||
| calls.rb:368:5:370:7 | instance |
|
||||
| calls.rb:379:9:381:11 | singleton1 |
|
||||
| calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:392:5:394:7 | call_singleton2 |
|
||||
| calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:431:9:437:11 | m3 |
|
||||
| calls.rb:434:13:436:15 | m4 |
|
||||
| calls.rb:444:13:446:15 | m5 |
|
||||
| calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:387:9:389:11 | factory |
|
||||
| calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:396:5:398:7 | call_singleton2 |
|
||||
| calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:443:9:449:11 | m3 |
|
||||
| calls.rb:446:13:448:15 | m4 |
|
||||
| calls.rb:456:13:458:15 | m5 |
|
||||
| calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:565:5:566:7 | singleton |
|
||||
| calls.rb:571:5:574:7 | mid_method |
|
||||
| calls.rb:577:5:578:7 | singleton2 |
|
||||
| calls.rb:584:5:585:7 | singleton1 |
|
||||
| calls.rb:587:5:589:7 | call_singleton1 |
|
||||
| calls.rb:591:5:593:7 | call_call_singleton1 |
|
||||
| calls.rb:597:5:598:7 | singleton1 |
|
||||
| calls.rb:600:5:602:7 | call_singleton1 |
|
||||
| calls.rb:606:5:607:7 | singleton1 |
|
||||
| calls.rb:609:5:611:7 | call_singleton1 |
|
||||
| hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:5:5:7:7 | world |
|
||||
| hello.rb:13:5:15:7 | message |
|
||||
@@ -456,8 +497,13 @@ publicMethod
|
||||
| private.rb:38:3:39:5 | public3 |
|
||||
| private.rb:66:3:67:5 | public |
|
||||
| private.rb:91:3:93:5 | call_m1 |
|
||||
| toplevel_self_singleton.rb:3:9:4:11 | ab_singleton_method |
|
||||
| toplevel_self_singleton.rb:13:5:15:7 | method_in_block |
|
||||
| toplevel_self_singleton.rb:19:5:21:7 | method_in_struct |
|
||||
| toplevel_self_singleton.rb:26:9:27:11 | call_me |
|
||||
| toplevel_self_singleton.rb:29:9:32:11 | call_you |
|
||||
protectedMethod
|
||||
| calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:534:15:536:7 | bar |
|
||||
| private.rb:32:3:33:5 | protected1 |
|
||||
| private.rb:35:3:36:5 | protected2 |
|
||||
|
||||
@@ -383,6 +383,10 @@ class SingletonOverride1
|
||||
def call_singleton1
|
||||
singleton1
|
||||
end
|
||||
|
||||
def factory
|
||||
self.new.instance1
|
||||
end
|
||||
end
|
||||
|
||||
def self.singleton2
|
||||
@@ -394,6 +398,10 @@ class SingletonOverride1
|
||||
end
|
||||
|
||||
singleton2
|
||||
|
||||
def instance1
|
||||
puts "SingletonOverride1#instance1"
|
||||
end
|
||||
end
|
||||
|
||||
SingletonOverride1.singleton1
|
||||
@@ -411,6 +419,10 @@ class SingletonOverride2 < SingletonOverride1
|
||||
def self.singleton2
|
||||
puts "SingletonOverride2#singleton2"
|
||||
end
|
||||
|
||||
def instance1
|
||||
puts "SingletonOverride2#instance1"
|
||||
end
|
||||
end
|
||||
|
||||
SingletonOverride2.singleton1
|
||||
@@ -548,3 +560,57 @@ ProtectedMethodsSub.new.baz
|
||||
|
||||
[C.new].each { |c| c.baz }
|
||||
["a","b","c"].each { |s| s.capitalize }
|
||||
|
||||
class SingletonUpCall_Base
|
||||
def self.singleton
|
||||
end
|
||||
end
|
||||
class SingletonUpCall_Sub < SingletonUpCall_Base
|
||||
singleton
|
||||
singleton2 # should not resolve
|
||||
def self.mid_method
|
||||
singleton
|
||||
singleton2 # should resolve
|
||||
end
|
||||
end
|
||||
class SingletonUpCall_SubSub < SingletonUpCall_Sub
|
||||
def self.singleton2
|
||||
end
|
||||
|
||||
mid_method
|
||||
end
|
||||
|
||||
class SingletonA
|
||||
def self.singleton1
|
||||
end
|
||||
|
||||
def self.call_singleton1
|
||||
singleton1
|
||||
end
|
||||
|
||||
def self.call_call_singleton1
|
||||
call_singleton1
|
||||
end
|
||||
end
|
||||
|
||||
class SingletonB < SingletonA
|
||||
def self.singleton1
|
||||
end
|
||||
|
||||
def self.call_singleton1
|
||||
singleton1 # should not be able to target `SingletonA:::singleton1` and `SingletonC:::singleton1`
|
||||
end
|
||||
end
|
||||
|
||||
class SingletonC < SingletonA
|
||||
def self.singleton1
|
||||
end
|
||||
|
||||
def self.call_singleton1
|
||||
singleton1 # should not be able to target `SingletonA:::singleton1` and `SingletonB:::singleton1`
|
||||
end
|
||||
end
|
||||
|
||||
SingletonA.call_call_singleton1
|
||||
SingletonB.call_call_singleton1
|
||||
SingletonC.call_call_singleton1
|
||||
|
||||
@@ -36,13 +36,15 @@ getMethod
|
||||
| calls.rb:325:1:329:3 | C1 | instance | calls.rb:326:5:328:7 | instance |
|
||||
| calls.rb:331:1:335:3 | C2 | instance | calls.rb:332:5:334:7 | instance |
|
||||
| calls.rb:337:1:341:3 | C3 | instance | calls.rb:338:5:340:7 | instance |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | m1 | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | m2 | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:484:1:490:3 | ExtendSingletonMethod | singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:513:1:517:3 | ProtectedMethodInModule | foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | bar | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | baz | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | baz | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | instance1 | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | instance1 | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | m1 | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | m2 | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:496:1:502:3 | ExtendSingletonMethod | singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:525:1:529:3 | ProtectedMethodInModule | foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | bar | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | baz | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | baz | calls.rb:551:5:554:7 | baz |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | world | hello.rb:5:5:7:7 | world |
|
||||
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
|
||||
@@ -314,82 +316,168 @@ lookupMethod
|
||||
| calls.rb:337:1:341:3 | C3 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:337:1:341:3 | C3 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:337:1:341:3 | C3 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:377:1:397:3 | SingletonOverride1 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:404:1:414:3 | SingletonOverride2 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | m1 | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | m2 | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:421:1:449:3 | ConditionalInstanceMethods | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:484:1:490:3 | ExtendSingletonMethod | singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:513:1:517:3 | ProtectedMethodInModule | foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | bar | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | baz | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:519:1:532:3 | ProtectedMethods | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | bar | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | baz | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:538:1:543:3 | ProtectedMethodsSub | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | instance1 | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:377:1:405:3 | SingletonOverride1 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | instance1 | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:412:1:426:3 | SingletonOverride2 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | m1 | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | m2 | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:433:1:461:3 | ConditionalInstanceMethods | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:496:1:502:3 | ExtendSingletonMethod | singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:525:1:529:3 | ProtectedMethodInModule | foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | bar | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | baz | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:531:1:544:3 | ProtectedMethods | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | bar | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | baz | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:550:1:555:3 | ProtectedMethodsSub | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:564:1:567:3 | SingletonUpCall_Base | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:568:1:575:3 | SingletonUpCall_Sub | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:576:1:581:3 | SingletonUpCall_SubSub | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:583:1:594:3 | SingletonA | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:583:1:594:3 | SingletonA | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:583:1:594:3 | SingletonA | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:583:1:594:3 | SingletonA | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:583:1:594:3 | SingletonA | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:583:1:594:3 | SingletonA | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:583:1:594:3 | SingletonA | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:583:1:594:3 | SingletonA | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:583:1:594:3 | SingletonA | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:583:1:594:3 | SingletonA | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:583:1:594:3 | SingletonA | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:583:1:594:3 | SingletonA | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:583:1:594:3 | SingletonA | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:583:1:594:3 | SingletonA | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:596:1:603:3 | SingletonB | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:596:1:603:3 | SingletonB | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:596:1:603:3 | SingletonB | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:596:1:603:3 | SingletonB | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:596:1:603:3 | SingletonB | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:596:1:603:3 | SingletonB | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:596:1:603:3 | SingletonB | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:596:1:603:3 | SingletonB | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:596:1:603:3 | SingletonB | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:596:1:603:3 | SingletonB | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:596:1:603:3 | SingletonB | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:596:1:603:3 | SingletonB | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:596:1:603:3 | SingletonB | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:596:1:603:3 | SingletonB | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| calls.rb:605:1:612:3 | SingletonC | add_singleton | calls.rb:367:1:371:3 | add_singleton |
|
||||
| calls.rb:605:1:612:3 | SingletonC | call_block | calls.rb:81:1:83:3 | call_block |
|
||||
| calls.rb:605:1:612:3 | SingletonC | call_instance_m | calls.rb:39:1:41:3 | call_instance_m |
|
||||
| calls.rb:605:1:612:3 | SingletonC | create | calls.rb:278:1:286:3 | create |
|
||||
| calls.rb:605:1:612:3 | SingletonC | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:605:1:612:3 | SingletonC | foo | calls.rb:85:1:89:3 | foo |
|
||||
| calls.rb:605:1:612:3 | SingletonC | funny | calls.rb:140:1:142:3 | funny |
|
||||
| calls.rb:605:1:612:3 | SingletonC | indirect | calls.rb:158:1:160:3 | indirect |
|
||||
| calls.rb:605:1:612:3 | SingletonC | new | calls.rb:117:5:117:16 | new |
|
||||
| calls.rb:605:1:612:3 | SingletonC | optional_arg | calls.rb:76:1:79:3 | optional_arg |
|
||||
| calls.rb:605:1:612:3 | SingletonC | pattern_dispatch | calls.rb:343:1:359:3 | pattern_dispatch |
|
||||
| calls.rb:605:1:612:3 | SingletonC | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:605:1:612:3 | SingletonC | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:605:1:612:3 | SingletonC | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| file://:0:0:0:0 | Class | include | calls.rb:108:5:110:7 | include |
|
||||
| file://:0:0:0:0 | Class | module_eval | calls.rb:107:5:107:24 | module_eval |
|
||||
| file://:0:0:0:0 | Class | new | calls.rb:117:5:117:16 | new |
|
||||
@@ -476,9 +564,6 @@ lookupMethod
|
||||
| modules_rec.rb:1:1:2:3 | B::A | new | calls.rb:117:5:117:16 | new |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | puts | calls.rb:102:5:102:30 | puts |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | new | calls.rb:117:5:117:16 | new |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | puts | calls.rb:102:5:102:30 | puts |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| private.rb:1:1:49:3 | E | new | calls.rb:117:5:117:16 | new |
|
||||
| private.rb:1:1:49:3 | E | private1 | private.rb:2:11:3:5 | private1 |
|
||||
| private.rb:1:1:49:3 | E | private2 | private.rb:8:3:9:5 | private2 |
|
||||
@@ -511,6 +596,9 @@ lookupMethod
|
||||
| private.rb:96:1:102:3 | PrivateOverride2 | private_on_main | private.rb:51:1:52:3 | private_on_main |
|
||||
| private.rb:96:1:102:3 | PrivateOverride2 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| private.rb:96:1:102:3 | PrivateOverride2 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| toplevel_self_singleton.rb:2:5:5:7 | A::B | new | calls.rb:117:5:117:16 | new |
|
||||
| toplevel_self_singleton.rb:2:5:5:7 | A::B | puts | calls.rb:102:5:102:30 | puts |
|
||||
| toplevel_self_singleton.rb:2:5:5:7 | A::B | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
enclosingMethod
|
||||
| calls.rb:2:5:2:14 | call to puts | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:2:5:2:14 | self | calls.rb:1:1:3:3 | foo |
|
||||
@@ -769,79 +857,102 @@ enclosingMethod
|
||||
| calls.rb:380:19:380:47 | SingletonOverride1#singleton1 | calls.rb:379:9:381:11 | singleton1 |
|
||||
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:384:13:384:22 | self | calls.rb:383:9:385:11 | call_singleton1 |
|
||||
| calls.rb:389:9:389:44 | call to puts | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:389:9:389:44 | self | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:389:14:389:44 | "SingletonOverride1#singleton2" | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:389:15:389:43 | SingletonOverride1#singleton2 | calls.rb:388:5:390:7 | singleton2 |
|
||||
| calls.rb:393:9:393:18 | call to singleton2 | calls.rb:392:5:394:7 | call_singleton2 |
|
||||
| calls.rb:393:9:393:18 | self | calls.rb:392:5:394:7 | call_singleton2 |
|
||||
| calls.rb:407:13:407:48 | call to puts | calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:407:13:407:48 | self | calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:407:18:407:48 | "SingletonOverride2#singleton1" | calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:407:19:407:47 | SingletonOverride2#singleton1 | calls.rb:406:9:408:11 | singleton1 |
|
||||
| calls.rb:412:9:412:44 | call to puts | calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:412:9:412:44 | self | calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:412:14:412:44 | "SingletonOverride2#singleton2" | calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:412:15:412:43 | SingletonOverride2#singleton2 | calls.rb:411:5:413:7 | singleton2 |
|
||||
| calls.rb:424:13:424:48 | call to puts | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:424:13:424:48 | self | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:424:18:424:48 | "ConditionalInstanceMethods#m1" | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:424:19:424:47 | ConditionalInstanceMethods#m1 | calls.rb:423:9:425:11 | m1 |
|
||||
| calls.rb:429:9:429:44 | call to puts | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:429:9:429:44 | self | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:429:14:429:44 | "ConditionalInstanceMethods#m2" | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:429:15:429:43 | ConditionalInstanceMethods#m2 | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:431:9:437:11 | m3 | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:432:13:432:48 | call to puts | calls.rb:431:9:437:11 | m3 |
|
||||
| calls.rb:432:13:432:48 | self | calls.rb:431:9:437:11 | m3 |
|
||||
| calls.rb:432:18:432:48 | "ConditionalInstanceMethods#m3" | calls.rb:431:9:437:11 | m3 |
|
||||
| calls.rb:432:19:432:47 | ConditionalInstanceMethods#m3 | calls.rb:431:9:437:11 | m3 |
|
||||
| calls.rb:434:13:436:15 | m4 | calls.rb:431:9:437:11 | m3 |
|
||||
| calls.rb:435:17:435:52 | call to puts | calls.rb:434:13:436:15 | m4 |
|
||||
| calls.rb:435:17:435:52 | self | calls.rb:434:13:436:15 | m4 |
|
||||
| calls.rb:435:22:435:52 | "ConditionalInstanceMethods#m4" | calls.rb:434:13:436:15 | m4 |
|
||||
| calls.rb:435:23:435:51 | ConditionalInstanceMethods#m4 | calls.rb:434:13:436:15 | m4 |
|
||||
| calls.rb:439:9:439:10 | call to m3 | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:439:9:439:10 | self | calls.rb:428:5:440:7 | m2 |
|
||||
| calls.rb:445:17:445:40 | call to puts | calls.rb:444:13:446:15 | m5 |
|
||||
| calls.rb:445:17:445:40 | self | calls.rb:444:13:446:15 | m5 |
|
||||
| calls.rb:445:22:445:40 | "AnonymousClass#m5" | calls.rb:444:13:446:15 | m5 |
|
||||
| calls.rb:445:23:445:39 | AnonymousClass#m5 | calls.rb:444:13:446:15 | m5 |
|
||||
| calls.rb:461:13:461:22 | call to puts | calls.rb:460:9:462:11 | foo |
|
||||
| calls.rb:461:13:461:22 | self | calls.rb:460:9:462:11 | foo |
|
||||
| calls.rb:461:18:461:22 | "foo" | calls.rb:460:9:462:11 | foo |
|
||||
| calls.rb:461:19:461:21 | foo | calls.rb:460:9:462:11 | foo |
|
||||
| calls.rb:467:13:467:22 | call to puts | calls.rb:466:9:468:11 | bar |
|
||||
| calls.rb:467:13:467:22 | self | calls.rb:466:9:468:11 | bar |
|
||||
| calls.rb:467:18:467:22 | "bar" | calls.rb:466:9:468:11 | bar |
|
||||
| calls.rb:467:19:467:21 | bar | calls.rb:466:9:468:11 | bar |
|
||||
| calls.rb:486:9:486:46 | call to puts | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:486:9:486:46 | self | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:486:14:486:46 | "ExtendSingletonMethod#singleton" | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:486:15:486:45 | ExtendSingletonMethod#singleton | calls.rb:485:5:487:7 | singleton |
|
||||
| calls.rb:515:9:515:42 | call to puts | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:515:9:515:42 | self | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:515:14:515:42 | "ProtectedMethodInModule#foo" | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:515:15:515:41 | ProtectedMethodInModule#foo | calls.rb:514:15:516:7 | foo |
|
||||
| calls.rb:523:9:523:35 | call to puts | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:523:9:523:35 | self | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:523:14:523:35 | "ProtectedMethods#bar" | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:523:15:523:34 | ProtectedMethods#bar | calls.rb:522:15:524:7 | bar |
|
||||
| calls.rb:527:9:527:11 | call to foo | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:527:9:527:11 | self | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:528:9:528:11 | call to bar | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:528:9:528:11 | self | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:529:9:529:24 | ProtectedMethods | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:529:9:529:28 | call to new | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:529:9:529:32 | call to foo | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:530:9:530:24 | ProtectedMethods | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:530:9:530:28 | call to new | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:530:9:530:32 | call to bar | calls.rb:526:5:531:7 | baz |
|
||||
| calls.rb:540:9:540:11 | call to foo | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:540:9:540:11 | self | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:541:9:541:27 | ProtectedMethodsSub | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:541:9:541:31 | call to new | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:541:9:541:35 | call to foo | calls.rb:539:5:542:7 | baz |
|
||||
| calls.rb:388:13:388:16 | self | calls.rb:387:9:389:11 | factory |
|
||||
| calls.rb:388:13:388:20 | call to new | calls.rb:387:9:389:11 | factory |
|
||||
| calls.rb:388:13:388:30 | call to instance1 | calls.rb:387:9:389:11 | factory |
|
||||
| calls.rb:393:9:393:44 | call to puts | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:393:9:393:44 | self | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:393:14:393:44 | "SingletonOverride1#singleton2" | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:393:15:393:43 | SingletonOverride1#singleton2 | calls.rb:392:5:394:7 | singleton2 |
|
||||
| calls.rb:397:9:397:18 | call to singleton2 | calls.rb:396:5:398:7 | call_singleton2 |
|
||||
| calls.rb:397:9:397:18 | self | calls.rb:396:5:398:7 | call_singleton2 |
|
||||
| calls.rb:403:9:403:43 | call to puts | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:403:9:403:43 | self | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:403:14:403:43 | "SingletonOverride1#instance1" | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:403:15:403:42 | SingletonOverride1#instance1 | calls.rb:402:5:404:7 | instance1 |
|
||||
| calls.rb:415:13:415:48 | call to puts | calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:415:13:415:48 | self | calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:415:18:415:48 | "SingletonOverride2#singleton1" | calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:415:19:415:47 | SingletonOverride2#singleton1 | calls.rb:414:9:416:11 | singleton1 |
|
||||
| calls.rb:420:9:420:44 | call to puts | calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:420:9:420:44 | self | calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:420:14:420:44 | "SingletonOverride2#singleton2" | calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:420:15:420:43 | SingletonOverride2#singleton2 | calls.rb:419:5:421:7 | singleton2 |
|
||||
| calls.rb:424:9:424:43 | call to puts | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:424:9:424:43 | self | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:424:14:424:43 | "SingletonOverride2#instance1" | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:424:15:424:42 | SingletonOverride2#instance1 | calls.rb:423:5:425:7 | instance1 |
|
||||
| calls.rb:436:13:436:48 | call to puts | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:436:13:436:48 | self | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:436:18:436:48 | "ConditionalInstanceMethods#m1" | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:436:19:436:47 | ConditionalInstanceMethods#m1 | calls.rb:435:9:437:11 | m1 |
|
||||
| calls.rb:441:9:441:44 | call to puts | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:441:9:441:44 | self | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:441:14:441:44 | "ConditionalInstanceMethods#m2" | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:441:15:441:43 | ConditionalInstanceMethods#m2 | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:443:9:449:11 | m3 | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:444:13:444:48 | call to puts | calls.rb:443:9:449:11 | m3 |
|
||||
| calls.rb:444:13:444:48 | self | calls.rb:443:9:449:11 | m3 |
|
||||
| calls.rb:444:18:444:48 | "ConditionalInstanceMethods#m3" | calls.rb:443:9:449:11 | m3 |
|
||||
| calls.rb:444:19:444:47 | ConditionalInstanceMethods#m3 | calls.rb:443:9:449:11 | m3 |
|
||||
| calls.rb:446:13:448:15 | m4 | calls.rb:443:9:449:11 | m3 |
|
||||
| calls.rb:447:17:447:52 | call to puts | calls.rb:446:13:448:15 | m4 |
|
||||
| calls.rb:447:17:447:52 | self | calls.rb:446:13:448:15 | m4 |
|
||||
| calls.rb:447:22:447:52 | "ConditionalInstanceMethods#m4" | calls.rb:446:13:448:15 | m4 |
|
||||
| calls.rb:447:23:447:51 | ConditionalInstanceMethods#m4 | calls.rb:446:13:448:15 | m4 |
|
||||
| calls.rb:451:9:451:10 | call to m3 | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:451:9:451:10 | self | calls.rb:440:5:452:7 | m2 |
|
||||
| calls.rb:457:17:457:40 | call to puts | calls.rb:456:13:458:15 | m5 |
|
||||
| calls.rb:457:17:457:40 | self | calls.rb:456:13:458:15 | m5 |
|
||||
| calls.rb:457:22:457:40 | "AnonymousClass#m5" | calls.rb:456:13:458:15 | m5 |
|
||||
| calls.rb:457:23:457:39 | AnonymousClass#m5 | calls.rb:456:13:458:15 | m5 |
|
||||
| calls.rb:473:13:473:22 | call to puts | calls.rb:472:9:474:11 | foo |
|
||||
| calls.rb:473:13:473:22 | self | calls.rb:472:9:474:11 | foo |
|
||||
| calls.rb:473:18:473:22 | "foo" | calls.rb:472:9:474:11 | foo |
|
||||
| calls.rb:473:19:473:21 | foo | calls.rb:472:9:474:11 | foo |
|
||||
| calls.rb:479:13:479:22 | call to puts | calls.rb:478:9:480:11 | bar |
|
||||
| calls.rb:479:13:479:22 | self | calls.rb:478:9:480:11 | bar |
|
||||
| calls.rb:479:18:479:22 | "bar" | calls.rb:478:9:480:11 | bar |
|
||||
| calls.rb:479:19:479:21 | bar | calls.rb:478:9:480:11 | bar |
|
||||
| calls.rb:498:9:498:46 | call to puts | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:498:9:498:46 | self | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:498:14:498:46 | "ExtendSingletonMethod#singleton" | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:498:15:498:45 | ExtendSingletonMethod#singleton | calls.rb:497:5:499:7 | singleton |
|
||||
| calls.rb:527:9:527:42 | call to puts | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:527:9:527:42 | self | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:527:14:527:42 | "ProtectedMethodInModule#foo" | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:527:15:527:41 | ProtectedMethodInModule#foo | calls.rb:526:15:528:7 | foo |
|
||||
| calls.rb:535:9:535:35 | call to puts | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:535:9:535:35 | self | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:535:14:535:35 | "ProtectedMethods#bar" | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:535:15:535:34 | ProtectedMethods#bar | calls.rb:534:15:536:7 | bar |
|
||||
| calls.rb:539:9:539:11 | call to foo | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:539:9:539:11 | self | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:540:9:540:11 | call to bar | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:540:9:540:11 | self | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:541:9:541:24 | ProtectedMethods | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:541:9:541:28 | call to new | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:541:9:541:32 | call to foo | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:542:9:542:24 | ProtectedMethods | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:542:9:542:28 | call to new | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:542:9:542:32 | call to bar | calls.rb:538:5:543:7 | baz |
|
||||
| calls.rb:552:9:552:11 | call to foo | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:552:9:552:11 | self | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:553:9:553:27 | ProtectedMethodsSub | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:553:9:553:31 | call to new | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:553:9:553:35 | call to foo | calls.rb:551:5:554:7 | baz |
|
||||
| calls.rb:572:9:572:17 | call to singleton | calls.rb:571:5:574:7 | mid_method |
|
||||
| calls.rb:572:9:572:17 | self | calls.rb:571:5:574:7 | mid_method |
|
||||
| calls.rb:573:9:573:18 | call to singleton2 | calls.rb:571:5:574:7 | mid_method |
|
||||
| calls.rb:573:9:573:18 | self | calls.rb:571:5:574:7 | mid_method |
|
||||
| calls.rb:588:9:588:18 | call to singleton1 | calls.rb:587:5:589:7 | call_singleton1 |
|
||||
| calls.rb:588:9:588:18 | self | calls.rb:587:5:589:7 | call_singleton1 |
|
||||
| calls.rb:592:9:592:23 | call to call_singleton1 | calls.rb:591:5:593:7 | call_call_singleton1 |
|
||||
| calls.rb:592:9:592:23 | self | calls.rb:591:5:593:7 | call_call_singleton1 |
|
||||
| calls.rb:601:9:601:18 | call to singleton1 | calls.rb:600:5:602:7 | call_singleton1 |
|
||||
| calls.rb:601:9:601:18 | self | calls.rb:600:5:602:7 | call_singleton1 |
|
||||
| calls.rb:610:9:610:18 | call to singleton1 | calls.rb:609:5:611:7 | call_singleton1 |
|
||||
| calls.rb:610:9:610:18 | self | calls.rb:609:5:611:7 | call_singleton1 |
|
||||
| hello.rb:3:9:3:22 | return | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:3:16:3:22 | "hello" | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:3:17:3:21 | hello | hello.rb:2:5:4:7 | hello |
|
||||
@@ -897,3 +1008,13 @@ enclosingMethod
|
||||
| private.rb:100:7:100:22 | PrivateOverride1 | private.rb:97:11:101:5 | m1 |
|
||||
| private.rb:100:7:100:26 | call to new | private.rb:97:11:101:5 | m1 |
|
||||
| private.rb:100:7:100:29 | call to m1 | private.rb:97:11:101:5 | m1 |
|
||||
| toplevel_self_singleton.rb:10:9:10:27 | call to ab_singleton_method | toplevel_self_singleton.rb:9:5:11:7 | method_in_block |
|
||||
| toplevel_self_singleton.rb:10:9:10:27 | self | toplevel_self_singleton.rb:9:5:11:7 | method_in_block |
|
||||
| toplevel_self_singleton.rb:14:9:14:27 | call to ab_singleton_method | toplevel_self_singleton.rb:13:5:15:7 | method_in_block |
|
||||
| toplevel_self_singleton.rb:14:9:14:27 | self | toplevel_self_singleton.rb:13:5:15:7 | method_in_block |
|
||||
| toplevel_self_singleton.rb:20:9:20:27 | call to ab_singleton_method | toplevel_self_singleton.rb:19:5:21:7 | method_in_struct |
|
||||
| toplevel_self_singleton.rb:20:9:20:27 | self | toplevel_self_singleton.rb:19:5:21:7 | method_in_struct |
|
||||
| toplevel_self_singleton.rb:30:13:30:19 | call to call_me | toplevel_self_singleton.rb:29:9:32:11 | call_you |
|
||||
| toplevel_self_singleton.rb:30:13:30:19 | self | toplevel_self_singleton.rb:29:9:32:11 | call_you |
|
||||
| toplevel_self_singleton.rb:31:13:31:20 | call to call_you | toplevel_self_singleton.rb:29:9:32:11 | call_you |
|
||||
| toplevel_self_singleton.rb:31:13:31:20 | self | toplevel_self_singleton.rb:29:9:32:11 | call_you |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -85,26 +85,44 @@ calls.rb:
|
||||
# 377| SingletonOverride1
|
||||
#-----| -> Object
|
||||
|
||||
# 404| SingletonOverride2
|
||||
# 412| SingletonOverride2
|
||||
#-----| -> SingletonOverride1
|
||||
|
||||
# 421| ConditionalInstanceMethods
|
||||
# 433| ConditionalInstanceMethods
|
||||
#-----| -> Object
|
||||
|
||||
# 484| ExtendSingletonMethod
|
||||
# 496| ExtendSingletonMethod
|
||||
|
||||
# 494| ExtendSingletonMethod2
|
||||
# 506| ExtendSingletonMethod2
|
||||
|
||||
# 500| ExtendSingletonMethod3
|
||||
# 512| ExtendSingletonMethod3
|
||||
|
||||
# 513| ProtectedMethodInModule
|
||||
# 525| ProtectedMethodInModule
|
||||
|
||||
# 519| ProtectedMethods
|
||||
# 531| ProtectedMethods
|
||||
#-----| -> Object
|
||||
|
||||
# 538| ProtectedMethodsSub
|
||||
# 550| ProtectedMethodsSub
|
||||
#-----| -> ProtectedMethods
|
||||
|
||||
# 564| SingletonUpCall_Base
|
||||
#-----| -> Object
|
||||
|
||||
# 568| SingletonUpCall_Sub
|
||||
#-----| -> SingletonUpCall_Base
|
||||
|
||||
# 576| SingletonUpCall_SubSub
|
||||
#-----| -> SingletonUpCall_Sub
|
||||
|
||||
# 583| SingletonA
|
||||
#-----| -> Object
|
||||
|
||||
# 596| SingletonB
|
||||
#-----| -> SingletonA
|
||||
|
||||
# 605| SingletonC
|
||||
#-----| -> SingletonA
|
||||
|
||||
hello.rb:
|
||||
# 1| EnglishWords
|
||||
|
||||
@@ -195,9 +213,6 @@ modules_rec.rb:
|
||||
# 1| B::A
|
||||
#-----| -> Object
|
||||
|
||||
# 4| A::B
|
||||
#-----| -> Object
|
||||
|
||||
private.rb:
|
||||
# 1| E
|
||||
#-----| -> Object
|
||||
@@ -209,3 +224,9 @@ private.rb:
|
||||
|
||||
# 96| PrivateOverride2
|
||||
#-----| -> PrivateOverride1
|
||||
|
||||
toplevel_self_singleton.rb:
|
||||
# 2| A::B
|
||||
#-----| -> Object
|
||||
|
||||
# 24| Good
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
module A
|
||||
class B
|
||||
def self.ab_singleton_method # should not be called
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do_something do
|
||||
def method_in_block
|
||||
ab_singleton_method # should not resolve to anything
|
||||
end
|
||||
obj=self
|
||||
def obj.method_in_block
|
||||
ab_singleton_method # should not resolve to anything
|
||||
end
|
||||
end
|
||||
|
||||
MyStruct = Struct.new(:foo, :bar) {
|
||||
def self.method_in_struct
|
||||
ab_singleton_method # should not resolve to anything
|
||||
end
|
||||
}
|
||||
|
||||
module Good
|
||||
class << self
|
||||
def call_me
|
||||
end
|
||||
|
||||
def call_you
|
||||
call_me
|
||||
call_you
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -23,10 +23,10 @@ nodes
|
||||
| ManuallyCheckHttpVerb.rb:59:10:59:38 | ...[...] | semmle.label | ...[...] |
|
||||
subpaths
|
||||
#select
|
||||
| ManuallyCheckHttpVerb.rb:4:8:4:19 | call to get? | ManuallyCheckHttpVerb.rb:4:8:4:19 | call to get? | ManuallyCheckHttpVerb.rb:4:8:4:19 | call to get? | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:12:8:12:22 | ... == ... | ManuallyCheckHttpVerb.rb:11:14:11:24 | call to env : | ManuallyCheckHttpVerb.rb:12:8:12:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:20:8:20:22 | ... == ... | ManuallyCheckHttpVerb.rb:19:14:19:35 | call to request_method : | ManuallyCheckHttpVerb.rb:20:8:20:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:28:8:28:22 | ... == ... | ManuallyCheckHttpVerb.rb:27:14:27:27 | call to method : | ManuallyCheckHttpVerb.rb:28:8:28:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:36:8:36:22 | ... == ... | ManuallyCheckHttpVerb.rb:35:14:35:39 | call to raw_request_method : | ManuallyCheckHttpVerb.rb:36:8:36:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:52:10:52:23 | ... == ... | ManuallyCheckHttpVerb.rb:51:16:51:44 | call to request_method_symbol : | ManuallyCheckHttpVerb.rb:52:10:52:23 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:59:10:59:38 | ...[...] | ManuallyCheckHttpVerb.rb:59:10:59:20 | call to env : | ManuallyCheckHttpVerb.rb:59:10:59:38 | ...[...] | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mappting resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:4:8:4:19 | call to get? | ManuallyCheckHttpVerb.rb:4:8:4:19 | call to get? | ManuallyCheckHttpVerb.rb:4:8:4:19 | call to get? | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:12:8:12:22 | ... == ... | ManuallyCheckHttpVerb.rb:11:14:11:24 | call to env : | ManuallyCheckHttpVerb.rb:12:8:12:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:20:8:20:22 | ... == ... | ManuallyCheckHttpVerb.rb:19:14:19:35 | call to request_method : | ManuallyCheckHttpVerb.rb:20:8:20:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:28:8:28:22 | ... == ... | ManuallyCheckHttpVerb.rb:27:14:27:27 | call to method : | ManuallyCheckHttpVerb.rb:28:8:28:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:36:8:36:22 | ... == ... | ManuallyCheckHttpVerb.rb:35:14:35:39 | call to raw_request_method : | ManuallyCheckHttpVerb.rb:36:8:36:22 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:52:10:52:23 | ... == ... | ManuallyCheckHttpVerb.rb:51:16:51:44 | call to request_method_symbol : | ManuallyCheckHttpVerb.rb:52:10:52:23 | ... == ... | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
| ManuallyCheckHttpVerb.rb:59:10:59:38 | ...[...] | ManuallyCheckHttpVerb.rb:59:10:59:20 | call to env : | ManuallyCheckHttpVerb.rb:59:10:59:38 | ...[...] | Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods. |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user