Merge remote-tracking branch 'origin/main' into ruby/rails-cookie-config

This commit is contained in:
Alex Ford
2021-12-22 17:54:03 +00:00
570 changed files with 60250 additions and 4920 deletions

View File

@@ -1 +1,20 @@
import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared::Consistency
import codeql.ruby.AST
import codeql.ruby.controlflow.internal.Completion
import codeql.ruby.controlflow.internal.ControlFlowGraphImpl
/**
* All `Expr` nodes are `PostOrderTree`s
*/
query predicate nonPostOrderExpr(Expr e, string cls) {
cls = e.getPrimaryQlClasses() and
not exists(e.getDesugared()) and
not e instanceof BeginExpr and
not e instanceof Namespace and
not e instanceof Toplevel and
exists(AstNode last, Completion c |
last(e, last, c) and
last != e and
c instanceof NormalCompletion
)
}

View File

@@ -82,7 +82,7 @@ module API {
* constructor is the function represented by this node.
*
* For example, if this node represents a use of some class `A`, then there might be a node
* representing instances of `A`, typically corresponding to expressions `new A()` at the
* representing instances of `A`, typically corresponding to expressions `A.new` at the
* source level.
*
* This predicate may have multiple results when there are multiple constructor calls invoking this API component.
@@ -244,7 +244,7 @@ module API {
MkUse(DataFlow::Node nd) { isUse(nd) }
private string resolveTopLevel(ConstantReadAccess read) {
TResolved(result) = resolveScopeExpr(read) and
TResolved(result) = resolveConstantReadAccess(read) and
not result.matches("%::%")
}

View File

@@ -675,3 +675,32 @@ module CookieSecurityConfigurationSetting {
abstract string getSecurityWarningMessage();
}
}
/**
* A data-flow node that logs data.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `Logging::Range` instead.
*/
class Logging extends DataFlow::Node {
Logging::Range range;
Logging() { this = range }
/** Gets an input that is logged. */
DataFlow::Node getAnInput() { result = range.getAnInput() }
}
/** Provides a class for modeling new logging mechanisms. */
module Logging {
/**
* A data-flow node that logs data.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `Logging` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets an input that is logged. */
abstract DataFlow::Node getAnInput();
}
}

View File

@@ -136,7 +136,7 @@ class ConstantReadAccess extends ConstantAccess {
this.hasGlobalScope() and
result = lookupConst(TResolved("Object"), this.getName())
or
result = lookupConst(resolveScopeExpr(this.getScopeExpr()), this.getName())
result = lookupConst(resolveConstantReadAccess(this.getScopeExpr()), this.getName())
}
override string getValueText() { result = this.getValue().getValueText() }
@@ -168,7 +168,7 @@ class ConstantWriteAccess extends ConstantAccess {
override string getAPrimaryQlClass() { result = "ConstantWriteAccess" }
/**
* Gets the fully qualified name for this constant, based on the context in
* Gets a fully qualified name for this constant, based on the context in
* which it is defined.
*
* For example, given
@@ -184,17 +184,31 @@ class ConstantWriteAccess extends ConstantAccess {
*
* the constant `Baz` has the fully qualified name `Foo::Bar::Baz`, and
* `CONST_A` has the fully qualified name `Foo::CONST_A`.
*
* Important note: This can return more than one value, because there are
* situations where there can be multiple possible "fully qualified" names.
* For example:
* ```
* module Mod4
* include Mod1
* module Mod3::Mod5 end
* end
* ```
* In the above snippet, `Mod5` has two valid fully qualified names it can be
* referred to by: `Mod1::Mod3::Mod5`, or `Mod4::Mod3::Mod5`.
*
* Another example has to do with the order in which module definitions are
* executed at runtime. Because of the way that ruby dynamically looks up
* constants up the namespace chain, the fully qualified name of a nested
* constant can be ambiguous from just statically looking at the AST.
*/
string getQualifiedName() {
/* get the qualified name for the parent module, then append w */
exists(ConstantWriteAccess parent | parent = this.getEnclosingModule() |
result = parent.getQualifiedName() + "::" + this.getName()
)
or
/* base case - there's no parent module */
not exists(ConstantWriteAccess parent | parent = this.getEnclosingModule()) and
result = this.getName()
}
string getAQualifiedName() { result = resolveConstantWriteAccess(this) }
/**
* Gets a qualified name for this constant. Deprecated in favor of
* `getAQualifiedName` because this can return more than one value
*/
deprecated string getQualifiedName() { result = this.getAQualifiedName() }
}
/**

View File

@@ -102,7 +102,7 @@ class IfExpr extends ConditionalExpr, TIfExpr {
cond = false and result = this.getElse()
}
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getThen" and result = this.getThen()
@@ -192,8 +192,8 @@ class UnlessExpr extends ConditionalExpr, TUnlessExpr {
final override string toString() { result = "unless ..." }
override AstNode getAChild(string pred) {
result = ConditionalExpr.super.getAChild(pred)
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getThen" and result = this.getThen()
or
@@ -229,8 +229,8 @@ class IfModifierExpr extends ConditionalExpr, TIfModifierExpr {
final override string toString() { result = "... if ..." }
override AstNode getAChild(string pred) {
result = ConditionalExpr.super.getAChild(pred)
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getBody" and result = this.getBody()
}
@@ -264,8 +264,8 @@ class UnlessModifierExpr extends ConditionalExpr, TUnlessModifierExpr {
final override string toString() { result = "... unless ..." }
override AstNode getAChild(string pred) {
result = ConditionalExpr.super.getAChild(pred)
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getBody" and result = this.getBody()
}
@@ -300,8 +300,8 @@ class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr {
final override string toString() { result = "... ? ... : ..." }
override AstNode getAChild(string pred) {
result = ConditionalExpr.super.getAChild(pred)
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getThen" and result = this.getThen()
or
@@ -361,22 +361,22 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
final Expr getValue() { result = super.getValue() }
/**
* Gets the `n`th branch of this case expression, either a `WhenExpr`, an
* Gets the `n`th branch of this case expression, either a `WhenClause`, an
* `InClause`, or a `StmtSequence`.
*/
final Expr getBranch(int n) { result = super.getBranch(n) }
final AstNode getBranch(int n) { result = super.getBranch(n) }
/**
* Gets a branch of this case expression, either a `WhenExpr`, an
* Gets a branch of this case expression, either a `WhenClause`, an
* `InClause`, or a `StmtSequence`.
*/
final Expr getABranch() { result = this.getBranch(_) }
final AstNode getABranch() { result = this.getBranch(_) }
/** Gets the `n`th `when` branch of this case expression. */
deprecated final WhenExpr getWhenBranch(int n) { result = this.getBranch(n) }
deprecated final WhenClause getWhenBranch(int n) { result = this.getBranch(n) }
/** Gets a `when` branch of this case expression. */
deprecated final WhenExpr getAWhenBranch() { result = this.getABranch() }
deprecated final WhenClause getAWhenBranch() { result = this.getABranch() }
/** Gets the `else` branch of this case expression, if any. */
final StmtSequence getElseBranch() { result = this.getABranch() }
@@ -390,7 +390,7 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
final override string toString() { result = "case ..." }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = ControlExpr.super.getAChild(pred)
or
pred = "getValue" and result = this.getValue()
@@ -401,6 +401,11 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
}
}
/**
* DEPRECATED: Use `WhenClause` instead.
*/
deprecated class WhenExpr = WhenClause;
/**
* A `when` branch of a `case` expression.
* ```rb
@@ -409,12 +414,12 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
* end
* ```
*/
class WhenExpr extends Expr, TWhenExpr {
class WhenClause extends AstNode, TWhenClause {
private Ruby::When g;
WhenExpr() { this = TWhenExpr(g) }
WhenClause() { this = TWhenClause(g) }
final override string getAPrimaryQlClass() { result = "WhenExpr" }
final override string getAPrimaryQlClass() { result = "WhenClause" }
/** Gets the body of this case-when expression. */
final Stmt getBody() { toGenerated(result) = g.getBody() }
@@ -444,7 +449,7 @@ class WhenExpr extends Expr, TWhenExpr {
final override string toString() { result = "when ..." }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getBody" and result = this.getBody()
@@ -461,7 +466,7 @@ class WhenExpr extends Expr, TWhenExpr {
* end
* ```
*/
class InClause extends Expr, TInClause {
class InClause extends AstNode, TInClause {
private Ruby::InClause g;
InClause() { this = TInClause(g) }
@@ -517,7 +522,7 @@ class InClause extends Expr, TInClause {
final override string toString() { result = "in ... then ..." }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getBody" and result = this.getBody()
@@ -552,7 +557,7 @@ class ConditionalLoop extends Loop, TConditionalLoop {
Expr getCondition() { none() }
override AstNode getAChild(string pred) {
result = Loop.super.getAChild(pred)
result = super.getAChild(pred)
or
pred = "getCondition" and result = this.getCondition()
}
@@ -692,7 +697,7 @@ class ForExpr extends Loop, TForExpr {
final override StmtSequence getBody() { toGenerated(result) = g.getBody() }
/** Gets the pattern representing the iteration argument. */
final Pattern getPattern() { toGenerated(result) = g.getPattern() }
final LhsExpr getPattern() { toGenerated(result) = g.getPattern() }
/**
* Gets the value being iterated over. In the following example, the result
@@ -707,8 +712,8 @@ class ForExpr extends Loop, TForExpr {
final override string toString() { result = "for ... in ..." }
override AstNode getAChild(string pred) {
result = Loop.super.getAChild(pred)
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getPattern" and result = this.getPattern()
or

View File

@@ -118,7 +118,7 @@ private class ErbDirectiveFile extends File {
/** Gets a statement in this file. */
pragma[nomagic]
Stmt getAStmt(int startLine, int startColumn) {
AstNode getAnAstNode(int startLine, int startColumn) {
exists(Location loc |
result.getLocation() = loc and
loc.getFile() = this and
@@ -142,13 +142,13 @@ class ErbDirective extends TDirectiveNode, ErbAstNode {
)
}
private predicate containsStmtStart(Stmt s) {
private predicate containsAstNodeStart(AstNode s) {
// `Toplevel` statements are not contained within individual directives,
// though their start location may appear within a directive location
not s instanceof Toplevel and
exists(ErbDirectiveFile file, int startLine, int startColumn |
this.spans(file, startLine) and
s = file.getAStmt(startLine, startColumn) and
s = file.getAnAstNode(startLine, startColumn) and
locationIncludesPosition(this.getLocation(), startLine, startColumn)
)
}
@@ -158,8 +158,8 @@ class ErbDirective extends TDirectiveNode, ErbAstNode {
* statement starting in this directive.
*/
Stmt getAChildStmt() {
this.containsStmtStart(result) and
not this.containsStmtStart(result.getParent())
this.containsAstNodeStart(result) and
not this.containsAstNodeStart(result.getParent())
}
/**

View File

@@ -66,6 +66,87 @@ class ArgumentList extends Expr, TArgumentList {
}
}
private class LhsExpr_ =
TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or
TDestructuredLhsExpr;
/**
* A "left-hand-side" (LHS) expression. An `LhsExpr` can occur on the left-hand side of
* operator assignments (`AssignOperation`), on the left-hand side of assignments
* (`AssignExpr`), as patterns in for loops (`ForExpr`), and as exception variables
* in `rescue` clauses (`RescueClause`).
*
* An `LhsExpr` can be a simple variable, a constant, a call, or an element reference:
*
* ```rb
* var = 1
* var += 1
* E = 1
* foo.bar = 1
* foo[0] = 1
* rescue E => var
* ```
*/
class LhsExpr extends Expr, LhsExpr_ {
LhsExpr() { lhsExpr(this) }
/** Gets a variable used in (or introduced by) this LHS. */
Variable getAVariable() { result = this.(VariableAccess).getVariable() }
}
/**
* A "left-hand-side" (LHS) expression of a destructured assignment.
*
* Examples:
* ```rb
* a, self.b = value
* (a, b), c[3] = value
* a, b, *rest, c, d = value
* ```
*/
class DestructuredLhsExpr extends LhsExpr, TDestructuredLhsExpr {
override string getAPrimaryQlClass() { result = "DestructuredLhsExpr" }
private DestructuredLhsExprImpl getImpl() { result = toGenerated(this) }
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
/** Gets the `i`th element in this destructured LHS. */
final Expr getElement(int i) {
exists(Ruby::AstNode c | c = this.getChild(i) |
toGenerated(result) = c.(Ruby::RestAssignment).getChild()
or
toGenerated(result) = c
)
}
/** Gets an element in this destructured LHS. */
final Expr getAnElement() { result = this.getElement(_) }
/**
* Gets the index of the element with the `*` marker on it, if it exists.
* In the example below the index is `2`.
* ```rb
* a, b, *rest, c, d = value
* ```
*/
final int getRestIndex() { result = this.getImpl().getRestIndex() }
override Variable getAVariable() {
result = this.getElement(_).(VariableWriteAccess).getVariable()
or
result = this.getElement(_).(DestructuredLhsExpr).getAVariable()
}
override string toString() { result = "(..., ...)" }
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getElement" and result = this.getElement(_)
}
}
/** A sequence of expressions. */
class StmtSequence extends Expr, TStmtSequence {
override string getAPrimaryQlClass() { result = "StmtSequence" }
@@ -136,7 +217,7 @@ class BodyStmt extends StmtSequence, TBodyStmt {
final predicate hasEnsure() { exists(this.getEnsure()) }
override AstNode getAChild(string pred) {
result = StmtSequence.super.getAChild(pred)
result = super.getAChild(pred)
or
pred = "getRescue" and result = this.getRescue(_)
or
@@ -214,7 +295,7 @@ class Pair extends Expr, TPair {
final override string toString() { result = "Pair" }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getKey" and result = this.getKey()
@@ -283,7 +364,7 @@ class RescueClause extends Expr, TRescueClause {
final override string toString() { result = "rescue ..." }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getException" and result = this.getException(_)
@@ -325,7 +406,7 @@ class RescueModifierExpr extends Expr, TRescueModifierExpr {
final override string toString() { result = "... rescue ..." }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getBody" and result = this.getBody()
@@ -386,7 +467,7 @@ class StringConcatenation extends Expr, TStringConcatenation {
final override string toString() { result = "\"...\" \"...\"" }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getString" and result = this.getString(_)

View File

@@ -35,36 +35,59 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
or
result = BodyStmt.super.getAChild(pred)
}
/** Holds if this method is private. */
predicate isPrivate() { none() }
}
/** A call to `private`. */
private class Private extends MethodCall {
Private() { this.getMethodName() = "private" }
/**
* A method call which modifies another method in some way.
* For example, `private :foo` makes the method `foo` private.
*/
private class MethodModifier extends MethodCall {
/** Gets the name of the method that this call applies to. */
Expr getMethodArgument() { result = this.getArgument(0) }
/** Gets the method that this `private` call applies to, if any */
Expr getMethod() { result = this.getArgument(0) }
/**
* Holds if this `private` call happens inside `c`, and refers to a
* method named `name`.
*/
/** Holds if this call modifies a method with name `name` in namespace `n`. */
pragma[noinline]
predicate isRef(ClassDeclaration c, string name) {
this = c.getAStmt() and
name = this.getMethod().(SymbolLiteral).getValueText()
predicate modifiesMethod(Namespace n, string name) {
this = n.getAStmt() and
[
this.getMethodArgument().(StringlikeLiteral).getValueText(),
this.getMethodArgument().(MethodBase).getName()
] = name
}
}
/**
* Holds if this `private` call happens at position `i` inside `c`,
* and the call has no arguments.
*/
pragma[noinline]
predicate hasNoArg(ClassDeclaration c, int i) {
this = c.getStmt(i) and
not exists(this.getMethod())
/** A call to `private` or `private_class_method`. */
private class Private extends MethodModifier {
private Namespace namespace;
private int position;
Private() { this.getMethodName() = "private" and namespace.getStmt(position) = this }
override predicate modifiesMethod(Namespace n, string name) {
n = namespace and
(
// def foo
// ...
// private :foo
super.modifiesMethod(n, name)
or
// private
// ...
// def foo
not exists(this.getMethodArgument()) and
exists(MethodBase m, int i | n.getStmt(i) = m and m.getName() = name and i > position)
)
}
}
/** A call to `private_class_method`. */
private class PrivateClassMethod extends MethodModifier {
PrivateClassMethod() { this.getMethodName() = "private_class_method" }
}
/** A normal method. */
class Method extends MethodBase, TMethod {
private Ruby::Method g;
@@ -90,12 +113,6 @@ class Method extends MethodBase, TMethod {
*/
final predicate isSetter() { g.getName() instanceof Ruby::Setter }
pragma[noinline]
private predicate isDeclaredIn(ClassDeclaration c, string name) {
this = c.getAStmt() and
name = this.getName()
}
/**
* Holds if this method is private. All methods with the name prefix
* `private` are private below:
@@ -122,18 +139,10 @@ class Method extends MethodBase, TMethod {
* end
* ```
*/
predicate isPrivate() {
this = any(Private p).getMethod()
or
exists(ClassDeclaration c, Private p, string name |
this.isDeclaredIn(c, name) and
p.isRef(c, name)
)
or
exists(ClassDeclaration c, Private p, int i, int j |
p.hasNoArg(c, i) and
this = c.getStmt(j) and
j > i
override predicate isPrivate() {
exists(Namespace n, string name |
any(Private p).modifiesMethod(n, name) and
isDeclaredIn(this, n, name)
)
or
// Top-level methods are private members of the Object class
@@ -147,6 +156,14 @@ class Method extends MethodBase, TMethod {
final override string toString() { result = this.getName() }
}
/**
* Holds if the method `m` has name `name` and is declared in namespace `n`.
*/
pragma[noinline]
private predicate isDeclaredIn(MethodBase m, Namespace n, string name) {
n = m.getEnclosingModule() and name = m.getName()
}
/** A singleton method. */
class SingletonMethod extends MethodBase, TSingletonMethod {
private Ruby::SingletonMethod g;
@@ -175,6 +192,36 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
or
pred = "getObject" and result = this.getObject()
}
/**
* Holds if this method is private. All methods with the name prefix
* `private` are private below:
*
* ```rb
* class C
* private_class_method def self.private1
* end
*
* def self.public
* end
*
* def self.private2
* end
* private_class_method :private2
*
* private # this has no effect on singleton methods
*
* def self.public2
* end
* end
* ```
*/
override predicate isPrivate() {
exists(Namespace n, string name |
any(PrivateClassMethod p).modifiesMethod(n, name) and
isDeclaredIn(this, n, name)
)
}
}
/**

View File

@@ -443,14 +443,14 @@ class NoRegExpMatchExpr extends BinaryOperation, TNoRegExpMatchExpr {
*/
class Assignment extends Operation instanceof AssignmentImpl {
/** Gets the left hand side of this assignment. */
final Pattern getLeftOperand() { result = super.getLeftOperandImpl() }
final LhsExpr getLeftOperand() { result = super.getLeftOperandImpl() }
/** Gets the right hand side of this assignment. */
final Expr getRightOperand() { result = super.getRightOperandImpl() }
final override string toString() { result = "... " + this.getOperator() + " ..." }
override AstNode getAChild(string pred) {
final override AstNode getAChild(string pred) {
result = Operation.super.getAChild(pred)
or
pred = "getLeftOperand" and result = this.getLeftOperand()

View File

@@ -7,7 +7,14 @@ private import internal.TreeSitter
/** A parameter. */
class Parameter extends AstNode, TParameter {
/** Gets the callable that this parameter belongs to. */
final Callable getCallable() { result.getAParameter() = this }
final Callable getCallable() {
result.getAParameter() = this
or
exists(DestructuredParameter parent |
this = parent.getAnElement() and
result = parent.getCallable()
)
}
/** Gets the zero-based position of this parameter. */
final int getPosition() { this = any(Callable c).getParameter(result) }
@@ -23,21 +30,63 @@ class Parameter extends AstNode, TParameter {
}
/**
* A parameter defined using destructuring. For example
*
* ```rb
* def tuples((a,b))
* puts "#{a} #{b}"
* end
* ```
*/
class DestructuredParameter extends Parameter, TDestructuredParameter {
private DestructuredParameterImpl getImpl() { result = toGenerated(this) }
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
/** Gets the `i`th element in this destructured parameter. */
final AstNode getElement(int i) {
exists(Ruby::AstNode c | c = this.getChild(i) | toGenerated(result) = c)
}
/** Gets an element in this destructured parameter. */
final AstNode getAnElement() { result = this.getElement(_) }
override LocalVariable getAVariable() {
result = this.getAnElement().(LocalVariableWriteAccess).getVariable()
or
result = this.getAnElement().(DestructuredParameter).getAVariable()
}
override string toString() { result = "(..., ...)" }
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getElement" and result = this.getElement(_)
}
final override string getAPrimaryQlClass() { result = "DestructuredParameter" }
}
/**
* DEPRECATED
*
* A parameter defined using a pattern.
*
* This includes both simple parameters and tuple parameters.
*/
class PatternParameter extends Parameter, Pattern, TPatternParameter {
deprecated class PatternParameter extends Parameter, Pattern, TPatternParameter {
override LocalVariable getAVariable() { result = Pattern.super.getAVariable() }
}
/** A parameter defined using a tuple pattern. */
class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatternParameter {
/**
* DEPRECATED
*
* A parameter defined using a tuple pattern.
*/
deprecated class TuplePatternParameter extends PatternParameter, TuplePattern,
TDestructuredParameter {
final override LocalVariable getAVariable() { result = TuplePattern.super.getAVariable() }
final override string getAPrimaryQlClass() { result = "TuplePatternParameter" }
override AstNode getAChild(string pred) { result = TuplePattern.super.getAChild(pred) }
}
/** A named parameter. */
@@ -72,7 +121,7 @@ class NamedParameter extends Parameter, TNamedParameter {
}
/** A simple (normal) parameter. */
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter instanceof SimpleParameterImpl {
class SimpleParameter extends NamedParameter, TSimpleParameter instanceof SimpleParameterImpl {
final override string getName() { result = SimpleParameterImpl.super.getNameImpl() }
final override LocalVariable getVariable() {

View File

@@ -6,8 +6,12 @@ private import internal.TreeSitter
private import internal.Variable
private import internal.Parameter
/** A pattern. */
class Pattern extends AstNode {
/**
* DEPRECATED
*
* A pattern.
*/
deprecated class Pattern extends AstNode {
Pattern() {
explicitAssignmentNode(toGenerated(this), _)
or
@@ -24,36 +28,18 @@ class Pattern extends AstNode {
Variable getAVariable() { none() }
}
private class LhsExpr_ =
TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or
TSimpleParameter;
/**
* A "left-hand-side" expression. An `LhsExpr` can occur on the left-hand side of
* operator assignments (`AssignOperation`), in patterns (`Pattern`) on the left-hand side of
* an assignment (`AssignExpr`) or for loop (`ForExpr`), and as the exception
* variable of a `rescue` clause (`RescueClause`).
* DEPRECATED
*
* An `LhsExpr` can be a simple variable, a constant, a call, or an element reference:
* ```rb
* var = 1
* var += 1
* E = 1
* foo.bar = 1
* foo[0] = 1
* rescue E => var
* ```
* A simple variable pattern.
*/
class LhsExpr extends Pattern, LhsExpr_, Expr {
deprecated class VariablePattern extends Pattern, LhsExpr, TVariableAccess {
override Variable getAVariable() { result = this.(VariableAccess).getVariable() }
}
private class TVariablePattern = TVariableAccess or TSimpleParameter;
/** A simple variable pattern. */
class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
/**
* DEPRECATED
*
* A tuple pattern.
*
* This includes both tuple patterns in parameters and assignments. Example patterns:
@@ -63,9 +49,7 @@ class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
* a, b, *rest, c, d = value
* ```
*/
class TuplePattern extends Pattern, TTuplePattern {
override string getAPrimaryQlClass() { result = "TuplePattern" }
deprecated class TuplePattern extends Pattern, TTuplePattern {
private TuplePatternImpl getImpl() { result = toGenerated(this) }
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
@@ -92,10 +76,6 @@ class TuplePattern extends Pattern, TTuplePattern {
final int getRestIndex() { result = this.getImpl().getRestIndex() }
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
override string toString() { result = "(..., ...)" }
override AstNode getAChild(string pred) { pred = "getElement" and result = this.getElement(_) }
}
private class TPatternNode =

View File

@@ -296,7 +296,7 @@ private module Cached {
TTokenSuperCall(Ruby::Super g) { vcall(g) } or
TToplevel(Ruby::Program g) or
TTrueLiteral(Ruby::True g) or
TTuplePatternParameter(Ruby::DestructuredParameter g) or
TDestructuredParameter(Ruby::DestructuredParameter g) or
TUnaryMinusExpr(Ruby::Unary g) { g instanceof @ruby_unary_minus } or
TUnaryPlusExpr(Ruby::Unary g) { g instanceof @ruby_unary_plus } or
TUndefStmt(Ruby::Undef g) or
@@ -305,7 +305,7 @@ private module Cached {
TUntilExpr(Ruby::Until g) or
TUntilModifierExpr(Ruby::UntilModifier g) or
TVariableReferencePattern(Ruby::VariableReferencePattern g) or
TWhenExpr(Ruby::When g) or
TWhenClause(Ruby::When g) or
TWhileExpr(Ruby::While g) or
TWhileModifierExpr(Ruby::WhileModifier g) or
TYieldCall(Ruby::Yield g)
@@ -321,9 +321,9 @@ private module Cached {
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatch or
TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or
TComplexLiteral or TDefinedExpr or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or
TDivExprReal or TDo or TDoBlock or TElementReference or TElse or TElsif or TEmptyStmt or
TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or
TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or
TDestructuredParameter or TDivExprReal or TDo or TDoBlock or TElementReference or TElse or
TElsif or TEmptyStmt or TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or
TFalseLiteral or TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or
TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or
THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExpr or
THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or TIf or
@@ -342,9 +342,9 @@ private module Cached {
TStringConcatenation or TStringEscapeSequenceComponent or TStringInterpolationComponent or
TStringTextComponent or TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or
TTernaryIfExpr or TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or
TToplevel or TTrueLiteral or TTuplePatternParameter or TUnaryMinusExpr or TUnaryPlusExpr or
TUndefStmt or TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
TVariableReferencePattern or TWhenExpr or TWhileExpr or TWhileModifierExpr or TYieldCall;
TToplevel or TTrueLiteral or TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or
TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
TVariableReferencePattern or TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall;
class TAstNodeSynth =
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
@@ -502,7 +502,7 @@ private module Cached {
n = TTokenSuperCall(result) or
n = TToplevel(result) or
n = TTrueLiteral(result) or
n = TTuplePatternParameter(result) or
n = TDestructuredParameter(result) or
n = TUnaryMinusExpr(result) or
n = TUnaryPlusExpr(result) or
n = TUndefStmt(result) or
@@ -511,7 +511,7 @@ private module Cached {
n = TUntilExpr(result) or
n = TUntilModifierExpr(result) or
n = TVariableReferencePattern(result) or
n = TWhenExpr(result) or
n = TWhenClause(result) or
n = TWhileExpr(result) or
n = TWhileModifierExpr(result) or
n = TYieldCall(result)
@@ -613,6 +613,15 @@ private module Cached {
or
result = toGenerated(n).getLocation()
}
cached
predicate lhsExpr(AST::Expr e) {
explicitAssignmentNode(toGenerated(e), _)
or
implicitAssignmentNode(toGenerated(e))
or
e = getSynthChild(any(AST::AssignExpr ae), 0)
}
}
import Cached
@@ -645,11 +654,12 @@ class TLoop = TConditionalLoop or TForExpr;
class TSelf = TSelfReal or TSelfSynth;
class TDestructuredLhsExpr = TDestructuredLeftAssignment or TLeftAssignmentList;
class TExpr =
TSelf or TArgumentList or TInClause or TRescueClause or TRescueModifierExpr or TPair or
TStringConcatenation or TCall or TBlockArgument or TConstantAccess or TControlExpr or
TWhenExpr or TLiteral or TCallable or TVariableAccess or TStmtSequence or TOperation or
TSimpleParameter or TForwardArgument;
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
TCall or TBlockArgument or TConstantAccess or TControlExpr or TLiteral or TCallable or
TVariableAccess or TStmtSequence or TOperation or TForwardArgument or TDestructuredLhsExpr;
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
@@ -778,18 +788,20 @@ class TStmt =
class TReturningStmt = TReturnStmt or TBreakStmt or TNextStmt;
class TParameter =
TPatternParameter or TBlockParameter or THashSplatParameter or THashSplatNilParameter or
TKeywordParameter or TOptionalParameter or TSplatParameter or TForwardParameter;
TSimpleParameter or TDestructuredParameter or TBlockParameter or THashSplatParameter or
THashSplatNilParameter or TKeywordParameter or TOptionalParameter or TSplatParameter or
TForwardParameter;
class TSimpleParameter = TSimpleParameterReal or TSimpleParameterSynth;
class TPatternParameter = TSimpleParameter or TTuplePatternParameter;
deprecated class TPatternParameter = TSimpleParameter or TDestructuredParameter;
class TNamedParameter =
TSimpleParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or
TOptionalParameter or TSplatParameter;
class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
deprecated class TTuplePattern =
TDestructuredParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
class TVariableAccess =
TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or

View File

@@ -5,17 +5,17 @@ private import codeql.ruby.ast.internal.AST
abstract class CaseExprImpl extends ControlExpr, TCase {
abstract Expr getValue();
abstract Expr getBranch(int n);
abstract AstNode getBranch(int n);
}
class CaseWhenExpr extends CaseExprImpl, TCaseExpr {
class CaseWhenClause extends CaseExprImpl, TCaseExpr {
private Ruby::Case g;
CaseWhenExpr() { this = TCaseExpr(g) }
CaseWhenClause() { this = TCaseExpr(g) }
final override Expr getValue() { toGenerated(result) = g.getValue() }
final override Expr getBranch(int n) {
final override AstNode getBranch(int n) {
toGenerated(result) = g.getChild(n) or
toGenerated(result) = g.getChild(n)
}
@@ -28,7 +28,7 @@ class CaseMatch extends CaseExprImpl, TCaseMatch {
final override Expr getValue() { toGenerated(result) = g.getValue() }
final override Expr getBranch(int n) {
final override AstNode getBranch(int n) {
toGenerated(result) = g.getClauses(n)
or
n = count(g.getClauses(_)) and toGenerated(result) = g.getElse()

View File

@@ -73,3 +73,29 @@ Ruby::AstNode getBodyStmtChild(TBodyStmt b, int i) {
or
result = any(Ruby::Begin g | b = TBeginExpr(g)).getChild(i)
}
abstract class DestructuredLhsExprImpl extends Ruby::AstNode {
abstract Ruby::AstNode getChildNode(int i);
final int getRestIndex() {
result = unique(int i | this.getChildNode(i) instanceof Ruby::RestAssignment)
}
}
class DestructuredLeftAssignmentImpl extends DestructuredLhsExprImpl,
Ruby::DestructuredLeftAssignment {
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
}
class LeftAssignmentListImpl extends DestructuredLhsExprImpl, Ruby::LeftAssignmentList {
override Ruby::AstNode getChildNode(int i) {
this =
any(Ruby::LeftAssignmentList lal |
if
strictcount(int j | exists(lal.getChild(j))) = 1 and
lal.getChild(0) instanceof Ruby::DestructuredLeftAssignment
then result = lal.getChild(0).(Ruby::DestructuredLeftAssignment).getChild(i)
else result = lal.getChild(i)
)
}
}

View File

@@ -36,7 +36,7 @@ private module Cached {
result = scopeAppend(namespaceDeclaration(n.getEnclosingModule()), n.getName())
or
exists(string container |
TResolved(container) = resolveScopeExpr(n.getScopeExpr()) and
TResolved(container) = resolveConstantReadAccess(n.getScopeExpr()) and
result = scopeAppend(container, n.getName())
)
}
@@ -58,29 +58,33 @@ private module Cached {
(
exists(ClassDeclaration d |
d = cls.getADeclaration() and
result = resolveScopeExpr(d.getSuperclassExpr())
result = resolveConstantReadAccess(d.getSuperclassExpr())
)
or
result = TResolved("Object") and
forex(ClassDeclaration d | d = cls.getADeclaration() |
not exists(resolveScopeExpr(d.getSuperclassExpr()))
not exists(resolveConstantReadAccess(d.getSuperclassExpr()))
)
)
}
private Module getACludedModule(IncludeOrPrependCall c, Module m) {
(
m = resolveConstantReadAccess(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.getReceiver() instanceof Self
) and
result = resolveConstantReadAccess(c.getAnArgument())
}
cached
Module getAnIncludedModule(Module m) {
m = TResolved("Object") and result = TResolved("Kernel")
or
exists(IncludeOrPrependCall c |
c.getMethodName() = "include" and
(
m = resolveScopeExpr(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.getReceiver() instanceof Self
) and
result = resolveScopeExpr(c.getAnArgument())
result = getACludedModule(c, m)
)
}
@@ -88,13 +92,7 @@ private module Cached {
Module getAPrependedModule(Module m) {
exists(IncludeOrPrependCall c |
c.getMethodName() = "prepend" and
(
m = resolveScopeExpr(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.getReceiver() instanceof Self
) and
result = resolveScopeExpr(c.getAnArgument())
result = getACludedModule(c, m)
)
}
@@ -102,13 +100,13 @@ private module Cached {
* Resolve class or module read access to a qualified module name.
*/
cached
TResolved resolveScopeExpr(ConstantReadAccess r) {
TResolved resolveConstantReadAccess(ConstantReadAccess r) {
exists(string qname | qname = resolveConstant(r) and result = TResolved(qname))
}
pragma[nomagic]
private string constantDefinition1(ConstantReadAccess r) {
exists(ConstantWriteAccess w | result = constantDefinition0(w) |
private string constantWriteAccess1(ConstantReadAccess r) {
exists(ConstantWriteAccess w | result = resolveConstantWriteAccess(w) |
r = w.getScopeExpr()
or
r = w.(ClassDeclaration).getSuperclassExpr()
@@ -117,8 +115,8 @@ private module Cached {
/**
* Resolve constant access (class, module or otherwise) to a qualified module name.
* `resolveScopeExpr/1` picks the best (lowest priority number) result of
* `resolveScopeExpr/2` that resolves to a constant definition. If the constant
* `resolveConstantReadAccess/1` picks the best (lowest priority number) result of
* `resolveConstantReadAccess/2` that resolves to a constant definition. If the constant
* definition is a Namespace then it is returned, if it's a constant assignment then
* the right-hand side of the assignment is resolved.
*/
@@ -127,10 +125,10 @@ private module Cached {
exists(string qname |
qname =
min(string qn, int p |
isDefinedConstant(qn) and
qn = resolveScopeExpr(r, p) and
qn = isDefinedConstant(_, _) and
qn = resolveConstantReadAccess(r, p) and
// prevent classes/modules that contain/extend themselves
not qn = constantDefinition1(r)
not qn = constantWriteAccess1(r)
|
qn order by p
)
@@ -138,7 +136,7 @@ private module Cached {
result = qname
or
exists(ConstantAssignment a |
qname = constantDefinition0(a) and
qname = resolveConstantWriteAccess(a) and
result = resolveConstant(a.getParent().(Assignment).getRightOperand())
)
)
@@ -154,7 +152,7 @@ private module Cached {
exists(AssignExpr ae, ConstantWriteAccess w |
w = ae.getLeftOperand() and
w.getName() = name and
m = resolveScopeExpr(w.getScopeExpr()) and
m = resolveConstantReadAccess(w.getScopeExpr()) and
result = ae.getRightOperand()
)
}
@@ -171,141 +169,313 @@ private predicate isToplevel(ConstantAccess n) {
)
}
private predicate isDefinedConstant(string qualifiedModuleName) {
qualifiedModuleName = [builtin(), constantDefinition0(_)]
}
private int maxDepth() { result = 1 + max(int level | exists(enclosing(_, level))) }
private ModuleBase enclosing(ModuleBase m, int level) {
result = m and level = 0
or
result = enclosing(m.getEnclosingModule(), level - 1)
}
pragma[noinline]
private Namespace enclosingNameSpaceConstantReadAccess(
ConstantReadAccess c, int priority, string name
) {
result = enclosing(c.getEnclosingModule(), priority) and
name = c.getName()
}
/**
* Resolve constant read access (typically a scope expression) to a qualified name. The
* `priority` value indicates the precedence of the solution with respect to the lookup order.
* A constant name without scope specifier is resolved against its enclosing modules (inner-most first);
* if the constant is not found in any of the enclosing modules, then the constant will be resolved
* with respect to the ancestors (prepends, includes, super classes, and their ancestors) of the
* directly enclosing module.
*/
private string resolveScopeExpr(ConstantReadAccess c, int priority) {
c.hasGlobalScope() and result = c.getName() and priority = 0
or
exists(string name |
result = qualifiedModuleName(resolveScopeExprConstantReadAccess(c, priority, name), name)
)
or
not exists(c.getScopeExpr()) and
not c.hasGlobalScope() and
(
exists(string name |
exists(Namespace n |
n = enclosingNameSpaceConstantReadAccess(c, priority, name) and
result = qualifiedModuleName(constantDefinition0(n), name)
)
or
result =
qualifiedModuleName(ancestors(qualifiedModuleNameConstantReadAccess(c, name),
priority - maxDepth()), name)
)
or
priority = maxDepth() + 4 and
qualifiedModuleNameConstantReadAccess(c, result) != "BasicObject"
)
}
pragma[nomagic]
private string resolveScopeExprConstantReadAccess(ConstantReadAccess c, int priority, string name) {
result = resolveScopeExpr(c.getScopeExpr(), priority) and
name = c.getName()
}
bindingset[qualifier, name]
private string scopeAppend(string qualifier, string name) {
if qualifier = "Object" then result = name else result = qualifier + "::" + name
}
private string qualifiedModuleName(ModuleBase m) {
result = "Object" and m instanceof Toplevel
or
result = constantDefinition0(m)
}
pragma[noinline]
private string qualifiedModuleNameConstantWriteAccess(ConstantWriteAccess c, string name) {
result = qualifiedModuleName(c.getEnclosingModule()) and
name = c.getName()
}
pragma[noinline]
private string qualifiedModuleNameConstantReadAccess(ConstantReadAccess c, string name) {
result = qualifiedModuleName(c.getEnclosingModule()) and
name = c.getName()
}
/**
* Get a qualified name for a constant definition. May return multiple qualified
* names because we over-approximate when resolving scope resolutions and ignore
* lookup order precedence. Taking lookup order into account here would lead to
* non-monotonic recursion.
* Provides predicates for resolving constant reads and writes to qualified names.
*
* Predicates suffixed with `NonRec` means that they do not depend recursively on
* `resolveConstantReadAccess`, while predicates suffixed with `Rec` do. This serves
* both as a performance optimization (minimize non-linear recursion), and as a way
* to prevent infinite recursion.
*/
private string constantDefinition0(ConstantWriteAccess c) {
c.hasGlobalScope() and result = c.getName()
or
result = scopeAppend(resolveScopeExpr(c.getScopeExpr(), _), c.getName())
or
not exists(c.getScopeExpr()) and
not c.hasGlobalScope() and
exists(string name | result = scopeAppend(qualifiedModuleNameConstantWriteAccess(c, name), name))
}
/**
* 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
* 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.
*/
// TODO: the order of super classes can be determined more precisely even without knowing the evaluation
// order, so we should be able to make this more precise.
private string ancestors(string qname, int priority) {
result = ancestors(prepends(qname), _) and priority = 0
or
result = qname and priority = 1 and isDefinedConstant(qname)
or
result = ancestors(includes(qname), _) and priority = 2
or
result = ancestors(superclass(qname), _) and priority = 3
}
private class IncludeOrPrependCall extends MethodCall {
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
string getAModule() { result = resolveScopeExpr(this.getAnArgument(), _) }
string getTarget() {
result = resolveScopeExpr(this.getReceiver(), _)
private module ResolveImpl {
private ModuleBase enclosing(ModuleBase m, int level) {
result = m and level = 0
or
result = qualifiedModuleName(enclosingModule(this)) and
(
this.getReceiver() instanceof Self
result = enclosing(m.getEnclosingModule(), level - 1)
}
private int maxDepth() { result = 1 + max(int level | exists(enclosing(_, level))) }
pragma[noinline]
private Namespace constantReadAccessEnclosingNameSpace(
ConstantReadAccess c, int priority, string name
) {
not exists(c.getScopeExpr()) and
not c.hasGlobalScope() and
result = enclosing(c.getEnclosingModule(), priority) and
name = c.getName()
}
pragma[nomagic]
private string enclosingQualifiedModuleNameNonRec(ConstantReadAccess c, string name) {
result = qualifiedModuleNameNonRec(c.getEnclosingModule(), _, _) and
name = c.getName() and
not exists(c.getScopeExpr()) and
not c.hasGlobalScope()
}
pragma[nomagic]
private string enclosingQualifiedModuleNameRec(ConstantReadAccess c, string name) {
result = qualifiedModuleNameRec(c.getEnclosingModule(), _, _) and
name = c.getName() and
not exists(c.getScopeExpr()) and
not c.hasGlobalScope()
}
pragma[nomagic]
private string resolveConstantReadAccessScopeNonRec(
ConstantReadAccess c, int priority, string name
) {
result = resolveConstantReadAccessNonRec(c.getScopeExpr(), priority) and
name = c.getName()
}
pragma[nomagic]
private string resolveConstantReadAccessScopeRec(ConstantReadAccess c, int priority, string name) {
result = resolveConstantReadAccessRec(c.getScopeExpr(), priority) and
name = c.getName()
}
pragma[nomagic]
private string resolveConstantReadAccessNonRec(ConstantReadAccess c, int priority) {
c.hasGlobalScope() and result = c.getName() and priority = 0
or
exists(string name, string s | result = isDefinedConstantNonRec(s, name) |
s = resolveConstantReadAccessScopeNonRec(c, priority, name)
)
or
exists(string name |
exists(Namespace n, string qname |
n = constantReadAccessEnclosingNameSpace(c, priority, name) and
qname = resolveConstantWriteAccessNonRec(n, _, _) and
result = isDefinedConstantNonRec(qname, name)
)
)
or
priority = maxDepth() + 4 and
enclosingQualifiedModuleNameNonRec(c, result) != "BasicObject"
}
pragma[nomagic]
private string resolveConstantReadAccessRec(ConstantReadAccess c, int priority) {
exists(string name, string s |
result = isDefinedConstantRec(s, name) and
s = resolveConstantReadAccessScopeNonRec(c, priority, name)
or
not exists(this.getReceiver())
result = isDefinedConstant(s, name) and
s = resolveConstantReadAccessScopeRec(c, priority, name)
)
or
exists(string name |
exists(Namespace n, string qname |
n = constantReadAccessEnclosingNameSpace(c, priority, name)
|
qname = resolveConstantWriteAccess(n) and
result = isDefinedConstantRec(qname, name)
or
qname = resolveConstantWriteAccessRec(n, _, _) and
result = isDefinedConstantNonRec(qname, name)
)
or
exists(string encl | result = qualifiedModuleNameAncestors(encl, name, priority) |
encl = enclosingQualifiedModuleNameNonRec(c, name)
or
encl = enclosingQualifiedModuleNameRec(c, name)
)
)
or
priority = maxDepth() + 4 and
enclosingQualifiedModuleNameRec(c, result) != "BasicObject"
}
/**
* Resolve constant read access (typically a scope expression) to a qualified name. The
* `priority` value indicates the precedence of the solution with respect to the lookup order.
* A constant name without scope specifier is resolved against its enclosing modules (inner-most first);
* if the constant is not found in any of the enclosing modules, then the constant will be resolved
* with respect to the ancestors (prepends, includes, super classes, and their ancestors) of the
* directly enclosing module.
*/
string resolveConstantReadAccess(ConstantReadAccess c, int priority) {
result = resolveConstantReadAccessNonRec(c, priority)
or
result = resolveConstantReadAccessRec(c, priority)
}
pragma[nomagic]
private string qualifiedModuleNameNonRec(ModuleBase m, string container, string name) {
result = "Object" and
m instanceof Toplevel and
container = "" and
name = result
or
result = resolveConstantWriteAccessNonRec(m, container, name)
}
pragma[nomagic]
private string qualifiedModuleNameRec(ModuleBase m, string container, string name) {
result = resolveConstantWriteAccessRec(m, container, name)
}
pragma[nomagic]
private string qualifiedModuleNameResolveConstantWriteAccessNonRec(
ConstantWriteAccess c, string name
) {
result = qualifiedModuleNameNonRec(c.getEnclosingModule(), _, _) and
name = c.getName()
}
pragma[nomagic]
private string qualifiedModuleNameResolveConstantWriteAccessRec(ConstantWriteAccess c, string name) {
result = qualifiedModuleNameRec(c.getEnclosingModule(), _, _) and
name = c.getName()
}
pragma[nomagic]
private string resolveConstantWriteAccessNonRec(
ConstantWriteAccess c, string container, string name
) {
c.hasGlobalScope() and
result = c.getName() and
container = "" and
name = result
or
result = scopeAppend(container, name) and
(
container = resolveConstantReadAccessNonRec(c.getScopeExpr(), _) and name = c.getName()
or
not exists(c.getScopeExpr()) and
not c.hasGlobalScope() and
container = qualifiedModuleNameResolveConstantWriteAccessNonRec(c, name)
)
}
pragma[nomagic]
private string resolveConstantWriteAccessRec(ConstantWriteAccess c, string container, string name) {
result = scopeAppend(container, name) and
(
container = resolveConstantReadAccessRec(c.getScopeExpr(), _) and name = c.getName()
or
not exists(c.getScopeExpr()) and
not c.hasGlobalScope() and
container = qualifiedModuleNameResolveConstantWriteAccessRec(c, name)
)
}
/**
* Get a qualified name for a constant definition. May return multiple qualified
* names because we over-approximate when resolving scope resolutions and ignore
* lookup order precedence. Taking lookup order into account here would lead to
* non-monotonic recursion.
*/
pragma[inline]
string resolveConstantWriteAccess(ConstantWriteAccess c) {
result = resolveConstantWriteAccessNonRec(c, _, _)
or
result = resolveConstantWriteAccessRec(c, _, _)
}
pragma[nomagic]
private string isDefinedConstantNonRec(string container, string name) {
result = resolveConstantWriteAccessNonRec(_, container, name)
or
result = builtin() and
name = result and
container = "Object"
}
pragma[nomagic]
private string isDefinedConstantRec(string container, string name) {
result = resolveConstantWriteAccessRec(_, container, name)
}
pragma[inline]
string isDefinedConstant(string container, string name) {
result = isDefinedConstantNonRec(container, name)
or
result = isDefinedConstantRec(container, name)
}
/**
* 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
* 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.
*/
// TODO: the order of super classes can be determined more precisely even without knowing the evaluation
// order, so we should be able to make this more precise.
private string ancestors(string qname, int priority) {
result = ancestors(prepends(qname), _) and priority = 0
or
result = qname and priority = 1 and qname = isDefinedConstant(_, _)
or
result = ancestors(includes(qname), _) and priority = 2
or
result = ancestors(superclass(qname), _) and priority = 3
}
pragma[nomagic]
private string qualifiedModuleNameAncestors(string encl, string name, int priority) {
result = isDefinedConstantNonRec(encl, name) and
priority = 1
or
// avoid infinite recursion
not exists(isDefinedConstantNonRec(encl, name)) and
result = isDefinedConstant(ancestors(encl, priority - maxDepth()), name)
}
class IncludeOrPrependCall extends MethodCall {
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
string getAModule() { result = resolveConstantReadAccess(this.getAnArgument(), _) }
string getTarget() {
result = resolveConstantReadAccess(this.getReceiver(), _)
or
exists(ModuleBase encl |
encl = enclosingModule(this) and
result = [qualifiedModuleNameNonRec(encl, _, _), qualifiedModuleNameRec(encl, _, _)]
|
this.getReceiver() instanceof Self
or
not exists(this.getReceiver())
)
}
}
pragma[nomagic]
private string prepends(string qname) {
exists(IncludeOrPrependCall m |
m.getMethodName() = "prepend" and
qname = m.getTarget() and
result = m.getAModule()
)
}
pragma[nomagic]
private string includes(string qname) {
qname = "Object" and
result = "Kernel"
or
exists(IncludeOrPrependCall m |
m.getMethodName() = "include" and
qname = m.getTarget() and
result = m.getAModule()
)
}
private Expr superexpr(string qname) {
exists(ClassDeclaration c |
qname = resolveConstantWriteAccess(c) and result = c.getSuperclassExpr()
)
}
pragma[nomagic]
private string superclass(string qname) {
qname = "Object" and result = "BasicObject"
or
result = resolveConstantReadAccess(superexpr(qname), _)
}
}
import ResolveImpl
/**
* A variant of AstNode::getEnclosingModule that excludes
* results that are enclosed in a block. This is a bit wrong because
@@ -323,45 +493,6 @@ private AstNode parent(AstNode n) {
not result instanceof Block
}
private string prepends(string qname) {
exists(IncludeOrPrependCall m |
m.getMethodName() = "prepend" and
qname = m.getTarget() and
result = m.getAModule()
)
}
private string includes(string qname) {
qname = "Object" and
result = "Kernel"
or
exists(IncludeOrPrependCall m |
m.getMethodName() = "include" and
qname = m.getTarget() and
result = m.getAModule()
)
}
private Expr superexpr(string qname) {
exists(ClassDeclaration c | qname = constantDefinition0(c) and result = c.getSuperclassExpr())
}
private string superclass(string qname) {
qname = "Object" and result = "BasicObject"
or
result = resolveScopeExpr(superexpr(qname), _)
}
private string qualifiedModuleName(string container, string name) {
isDefinedConstant(result) and
(
container = result.regexpCapture("(.+)::([^:]+)", 1) and
name = result.regexpCapture("(.+)::([^:]+)", 2)
or
container = "Object" and name = result
)
}
private Module getAncestors(Module m) {
result = m or
result = getAncestors(m.getAnIncludedModule()) or

View File

@@ -154,7 +154,7 @@ class BitwiseXorSynthExpr extends BinaryOperationSynth, TBitwiseXorExprSynth {
}
abstract class AssignmentImpl extends OperationImpl, TAssignment {
abstract Pattern getLeftOperandImpl();
abstract Expr getLeftOperandImpl();
abstract Expr getRightOperandImpl();
@@ -172,7 +172,7 @@ class AssignExprReal extends AssignmentImpl, TAssignExprReal {
final override string getOperatorImpl() { result = "=" }
final override Pattern getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
final override Expr getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
final override Expr getRightOperandImpl() { toGenerated(result) = g.getRight() }
}
@@ -180,7 +180,7 @@ class AssignExprReal extends AssignmentImpl, TAssignExprReal {
class AssignExprSynth extends AssignmentImpl, TAssignExprSynth {
final override string getOperatorImpl() { result = "=" }
final override Pattern getLeftOperandImpl() { synthChild(this, 0, result) }
final override Expr getLeftOperandImpl() { synthChild(this, 0, result) }
final override Expr getRightOperandImpl() { synthChild(this, 1, result) }
}
@@ -192,7 +192,7 @@ class AssignOperationImpl extends AssignmentImpl, TAssignOperation {
final override string getOperatorImpl() { result = g.getOperator() }
final override Pattern getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
final override Expr getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
final override Expr getRightOperandImpl() { toGenerated(result) = g.getRight() }
}

View File

@@ -44,3 +44,7 @@ class SimpleParameterSynthImpl extends SimpleParameterImpl, TSimpleParameterSynt
override string getNameImpl() { result = this.getVariableImpl().getName() }
}
class DestructuredParameterImpl extends Ruby::DestructuredParameter {
Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
}

View File

@@ -1,36 +1,28 @@
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.Expr
private import codeql.ruby.ast.internal.Parameter
private import AST
private import TreeSitter
abstract class TuplePatternImpl extends Ruby::AstNode {
abstract Ruby::AstNode getChildNode(int i);
deprecated class TuplePatternImpl extends Ruby::AstNode {
TuplePatternImpl() {
this instanceof DestructuredParameterImpl or
this instanceof DestructuredLhsExprImpl
}
Ruby::AstNode getChildNode(int i) {
result =
[
this.(DestructuredParameterImpl).getChildNode(i),
this.(DestructuredLhsExprImpl).getChildNode(i)
]
}
final int getRestIndex() {
result = unique(int i | this.getChildNode(i) instanceof Ruby::RestAssignment)
}
}
class TuplePatternParameterImpl extends TuplePatternImpl, Ruby::DestructuredParameter {
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
}
class DestructuredLeftAssignmentImpl extends TuplePatternImpl, Ruby::DestructuredLeftAssignment {
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
}
class LeftAssignmentListImpl extends TuplePatternImpl, Ruby::LeftAssignmentList {
override Ruby::AstNode getChildNode(int i) {
this =
any(Ruby::LeftAssignmentList lal |
if
strictcount(int j | exists(lal.getChild(j))) = 1 and
lal.getChild(0) instanceof Ruby::DestructuredLeftAssignment
then result = lal.getChild(0).(Ruby::DestructuredLeftAssignment).getChild(i)
else result = lal.getChild(i)
)
}
}
/**
* Holds if `node` is a case pattern.
*/

View File

@@ -636,36 +636,36 @@ private module AssignOperationDesugar {
}
}
private module CompoundAssignDesugar {
/** An assignment where the left-hand side is a tuple pattern. */
private class TupleAssignExpr extends AssignExpr {
private TuplePattern tp;
private module DestructuredAssignDesugar {
/** A destructured assignment. */
private class DestructuredAssignExpr extends AssignExpr {
private DestructuredLhsExpr lhs;
pragma[nomagic]
TupleAssignExpr() { tp = this.getLeftOperand() }
DestructuredAssignExpr() { lhs = this.getLeftOperand() }
TuplePattern getTuplePattern() { result = tp }
DestructuredLhsExpr getLhs() { result = lhs }
pragma[nomagic]
Pattern getElement(int i) { result = tp.getElement(i) }
Expr getElement(int i) { result = lhs.getElement(i) }
pragma[nomagic]
int getNumberOfElements() {
toGenerated(tp) = any(TuplePatternImpl impl | result = count(impl.getChildNode(_)))
toGenerated(lhs) = any(DestructuredLhsExprImpl impl | result = count(impl.getChildNode(_)))
}
pragma[nomagic]
int getRestIndexOrNumberOfElements() {
result = tp.getRestIndex()
result = lhs.getRestIndex()
or
toGenerated(tp) = any(TuplePatternImpl impl | not exists(impl.getRestIndex())) and
toGenerated(lhs) = any(DestructuredLhsExprImpl impl | not exists(impl.getRestIndex())) and
result = this.getNumberOfElements()
}
}
pragma[nomagic]
private predicate compoundAssignSynthesis(AstNode parent, int i, Child child) {
exists(TupleAssignExpr tae |
private predicate destructuredAssignSynthesis(AstNode parent, int i, Child child) {
exists(DestructuredAssignExpr tae |
parent = tae and
i = -1 and
child = SynthChild(StmtSequenceKind())
@@ -689,8 +689,8 @@ private module CompoundAssignDesugar {
child = childRef(tae.getRightOperand())
)
or
exists(Pattern p, int j, int restIndex |
p = tae.getElement(j) and
exists(AstNode elem, int j, int restIndex |
elem = tae.getElement(j) and
restIndex = tae.getRestIndexOrNumberOfElements()
|
parent = seq and
@@ -700,7 +700,7 @@ private module CompoundAssignDesugar {
exists(AstNode assign | assign = TAssignExprSynth(seq, j + 1) |
parent = assign and
i = 0 and
child = childRef(p)
child = childRef(elem)
or
parent = assign and
i = 1 and
@@ -756,26 +756,26 @@ private module CompoundAssignDesugar {
* z = __synth__0[-1];
* ```
*/
private class CompoundAssignSynthesis extends Synthesis {
private class DestructuredAssignSynthesis extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
compoundAssignSynthesis(parent, i, child)
destructuredAssignSynthesis(parent, i, child)
}
final override predicate location(AstNode n, Location l) {
exists(TupleAssignExpr tae, StmtSequence seq | seq = tae.getDesugared() |
exists(DestructuredAssignExpr tae, StmtSequence seq | seq = tae.getDesugared() |
n = seq.getStmt(0) and
hasLocation(tae.getRightOperand(), l)
or
exists(Pattern p, int j |
p = tae.getElement(j) and
exists(AstNode elem, int j |
elem = tae.getElement(j) and
n = seq.getStmt(j + 1) and
hasLocation(p, l)
hasLocation(elem, l)
)
)
}
final override predicate localVariable(AstNode n, int i) {
n instanceof TupleAssignExpr and
n instanceof DestructuredAssignExpr and
i = 0
}
@@ -784,10 +784,6 @@ private module CompoundAssignDesugar {
setter = false and
arity = 1
}
final override predicate excludeFromControlFlowTree(AstNode n) {
n = any(TupleAssignExpr tae).getTuplePattern()
}
}
}
@@ -820,7 +816,7 @@ private module ArrayLiteralDesugar {
* ::Array.[](1, 2, 3)
* ```
*/
private class CompoundAssignSynthesis extends Synthesis {
private class ArrayLiteralSynthesis extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
arrayLiteralSynthesis(parent, i, child)
}

View File

@@ -338,7 +338,7 @@ module ExprNodes {
}
private class CaseExprChildMapping extends ExprChildMapping, CaseExpr {
override predicate relevantChild(Expr e) { e = this.getValue() or e = this.getBranch(_) }
override predicate relevantChild(Expr e) { e = this.getValue() }
}
/** A control-flow node that wraps a `MethodCall` AST expression. */
@@ -356,11 +356,6 @@ module ExprNodes {
/** Gets the expression being compared, if any. */
final ExprCfgNode getValue() { e.hasCfgChild(e.getValue(), this, result) }
/**
* Gets the `n`th branch of this case expression.
*/
final ExprCfgNode getBranch(int n) { e.hasCfgChild(e.getBranch(n), this, result) }
}
private class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr {

View File

@@ -23,7 +23,7 @@ private newtype TCompletion =
TRetryCompletion() or
TRaiseCompletion() or // TODO: Add exception type?
TExitCompletion() or
TNestedCompletion(Completion inner, Completion outer, int nestLevel) {
TNestedCompletion(TCompletion inner, TCompletion outer, int nestLevel) {
inner = TBreakCompletion() and
outer instanceof NonNestedNormalCompletion and
nestLevel = 0
@@ -37,7 +37,7 @@ private newtype TCompletion =
}
pragma[noinline]
private predicate nestedEnsureCompletion(Completion outer, int nestLevel) {
private predicate nestedEnsureCompletion(TCompletion outer, int nestLevel) {
(
outer = TReturnCompletion()
or
@@ -107,11 +107,7 @@ abstract class Completion extends TCompletion {
n = any(RescueModifierExpr parent).getBody() and
this = [TSimpleCompletion().(TCompletion), TRaiseCompletion()]
or
(
mayRaise(n)
or
n instanceof CaseMatch and not exists(n.(CaseExpr).getElseBranch())
) and
mayRaise(n) and
(
this = TRaiseCompletion()
or
@@ -209,7 +205,7 @@ private predicate inBooleanContext(AstNode n) {
or
n = any(StmtSequence parent | inBooleanContext(parent)).getLastStmt()
or
exists(CaseExpr c, WhenExpr w |
exists(CaseExpr c, WhenClause w |
not exists(c.getValue()) and
c.getABranch() = w and
w.getPattern(_) = n
@@ -231,7 +227,7 @@ private predicate mustHaveMatchingCompletion(AstNode n) {
private predicate inMatchingContext(AstNode n) {
n = any(RescueClause r).getException(_)
or
exists(CaseExpr c, WhenExpr w |
exists(CaseExpr c, WhenClause w |
exists(c.getValue()) and
c.getABranch() = w and
w.getPattern(_) = n

View File

@@ -107,14 +107,8 @@ module Trees {
}
}
private class ArgumentListTree extends StandardTree, ArgumentList {
private class ArgumentListTree extends StandardPostOrderTree, ArgumentList {
final override ControlFlowTree getChildElement(int i) { result = this.getElement(i) }
final override predicate first(AstNode first) { first(this.getFirstChildElement(), first) }
final override predicate last(AstNode last, Completion c) {
last(this.getLastChildElement(), last, c)
}
}
private class AssignExprTree extends StandardPostOrderTree, AssignExpr {
@@ -252,7 +246,7 @@ module Trees {
)
or
// Last element from any matching `rescue` block continues to the `ensure` block
this.getRescue(_).(RescueTree).lastMatch(result, c) and
last(this.getRescue(_), result, c) and
ensurable = true
or
// If the last `rescue` block does not match, continue to the `ensure` block
@@ -378,35 +372,18 @@ module Trees {
override ControlFlowTree getChildElement(int i) { result = this.getArgument(i) }
}
private class CaseTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseExpr {
private class CaseTree extends PostOrderTree, CaseExpr, ASTInternal::TCaseExpr {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getValue() or child = this.getABranch()
}
final override predicate last(AstNode last, Completion c) {
last(this.getValue(), last, c) and not exists(this.getABranch())
final override predicate first(AstNode first) {
first(this.getValue(), first)
or
last(this.getABranch().(WhenExpr).getBody(), last, c)
or
exists(int i, ControlFlowTree lastBranch |
lastBranch = this.getBranch(i) and
not exists(this.getBranch(i + 1)) and
last(lastBranch, last, c)
)
not exists(this.getValue()) and first(this.getBranch(0), first)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
exists(AstNode next |
pred = this and
first(next, succ) and
c instanceof SimpleCompletion
|
next = this.getValue()
or
not exists(this.getValue()) and
next = this.getBranch(0)
)
or
last(this.getValue(), pred, c) and
first(this.getBranch(0), succ) and
c instanceof SimpleCompletion
@@ -416,20 +393,35 @@ module Trees {
first(this.getBranch(i + 1), succ) and
c.(ConditionalCompletion).getValue() = false
)
or
succ = this and
c instanceof NormalCompletion and
(
last(this.getValue(), pred, c) and not exists(this.getABranch())
or
last(this.getABranch().(WhenClause).getBody(), pred, c)
or
exists(int i, ControlFlowTree lastBranch |
lastBranch = this.getBranch(i) and
not exists(this.getBranch(i + 1)) and
last(lastBranch, pred, c)
)
)
}
}
private class CaseMatchTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseMatch {
private class CaseMatchTree extends PostOrderTree, CaseExpr, ASTInternal::TCaseMatch {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getValue() or child = this.getABranch()
}
final override predicate first(AstNode first) { first(this.getValue(), first) }
final override predicate last(AstNode last, Completion c) {
last(this.getABranch(), last, c) and
not c.(MatchingCompletion).getValue() = false
super.last(last, c)
or
not exists(this.getElseBranch()) and
exists(MatchingCompletion lc, Expr lastBranch |
exists(MatchingCompletion lc, AstNode lastBranch |
lastBranch = max(int i | | this.getBranch(i) order by i) and
lc.getValue() = false and
last(lastBranch, last, lc) and
@@ -439,19 +431,24 @@ module Trees {
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
pred = this and
first(this.getValue(), succ) and
c instanceof SimpleCompletion
or
last(this.getValue(), pred, c) and
first(this.getBranch(0), succ) and
c instanceof SimpleCompletion
or
exists(int i, Expr branch | branch = this.getBranch(i) |
exists(int i, AstNode branch | branch = this.getBranch(i) |
last(branch, pred, c) and
first(this.getBranch(i + 1), succ) and
c.(MatchingCompletion).getValue() = false
)
or
succ = this and
c instanceof NormalCompletion and
(
last(this.getABranch(), pred, c) and
not c.(MatchingCompletion).getValue() = false
or
last(this.getElseBranch(), pred, c)
)
}
}
@@ -935,6 +932,10 @@ module Trees {
}
}
private class DestructuredParameterTree extends StandardPostOrderTree, DestructuredParameter {
final override ControlFlowTree getChildElement(int i) { result = this.getElement(i) }
}
private class DesugaredTree extends ControlFlowTree {
ControlFlowTree desugared;
@@ -977,6 +978,8 @@ module Trees {
}
}
private class ForwardedArgumentsTree extends LeafTree, ForwardedArguments { }
private class ForwardParameterTree extends LeafTree, ForwardParameter { }
private class GlobalVariableTree extends LeafTree, GlobalVariableAccess { }
@@ -989,7 +992,7 @@ module Trees {
private class HashSplatParameterTree extends NonDefaultValueParameterTree, HashSplatParameter { }
private class HereDocTree extends StandardPreOrderTree, HereDoc {
private class HereDocTree extends StandardPostOrderTree, HereDoc {
final override ControlFlowTree getChildElement(int i) { result = this.getComponent(i) }
}
@@ -1151,90 +1154,70 @@ module Trees {
private class RedoStmtTree extends LeafTree, RedoStmt { }
private class RescueModifierTree extends PreOrderTree, RescueModifierExpr {
private class RescueModifierTree extends PostOrderTree, RescueModifierExpr {
final override predicate propagatesAbnormal(AstNode child) { child = this.getHandler() }
final override predicate last(AstNode last, Completion c) {
last(this.getBody(), last, c) and
not c instanceof RaiseCompletion
or
last(this.getHandler(), last, c)
}
final override predicate first(AstNode first) { first(this.getBody(), first) }
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
pred = this and
first(this.getBody(), succ) and
c instanceof SimpleCompletion
or
last(this.getBody(), pred, c) and
c instanceof RaiseCompletion and
first(this.getHandler(), succ)
(
c instanceof RaiseCompletion and
first(this.getHandler(), succ)
or
not c instanceof RaiseCompletion and
succ = this
)
or
last(this.getHandler(), pred, c) and
c instanceof NormalCompletion and
succ = this
}
}
private class RescueTree extends PreOrderTree, RescueClause {
final override predicate propagatesAbnormal(AstNode child) { child = this.getAnException() }
private Expr getLastException() {
exists(int i | result = this.getException(i) and not exists(this.getException(i + 1)))
private class RescueTree extends PostOrderTree, RescueClause {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getAnException() or
child = this.getBody()
}
predicate lastMatch(AstNode last, Completion c) {
last(this.getBody(), last, c)
final override predicate first(AstNode first) {
first(this.getException(0), first)
or
not exists(this.getBody()) and
not exists(this.getException(0)) and
(
last(this.getVariableExpr(), last, c)
first(this.getVariableExpr(), first)
or
not exists(this.getVariableExpr()) and
(
last(this.getAnException(), last, c) and
c.(MatchingCompletion).getValue() = true
first(this.getBody(), first)
or
not exists(this.getAnException()) and
last = this and
c.isValidFor(this)
not exists(this.getBody()) and first = this
)
)
}
private Expr getLastException() {
exists(int i | result = this.getException(i) and not exists(this.getException(i + 1)))
}
predicate lastNoMatch(AstNode last, Completion c) {
last(this.getLastException(), last, c) and
c.(MatchingCompletion).getValue() = false
}
final override predicate last(AstNode last, Completion c) {
this.lastNoMatch(last, c)
or
this.lastMatch(last, c)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
exists(AstNode next |
pred = this and
first(next, succ) and
c instanceof SimpleCompletion
|
next = this.getException(0)
or
not exists(this.getException(0)) and
(
next = this.getVariableExpr()
or
not exists(this.getVariableExpr()) and
next = this.getBody()
)
)
or
exists(AstNode next |
last(this.getAnException(), pred, c) and
first(next, succ) and
c.(MatchingCompletion).getValue() = true
|
next = this.getVariableExpr()
last(this.getAnException(), pred, c) and
c.(MatchingCompletion).getValue() = true and
(
first(this.getVariableExpr(), succ)
or
not exists(this.getVariableExpr()) and
next = this.getBody()
(
first(this.getBody(), succ)
or
not exists(this.getBody()) and succ = this
)
)
or
exists(int i |
@@ -1244,8 +1227,16 @@ module Trees {
)
or
last(this.getVariableExpr(), pred, c) and
first(this.getBody(), succ) and
c instanceof NormalCompletion
c instanceof NormalCompletion and
(
first(this.getBody(), succ)
or
not exists(this.getBody()) and succ = this
)
or
last(this.getBody(), pred, c) and
c instanceof NormalCompletion and
succ = this
}
}
@@ -1349,14 +1340,8 @@ module Trees {
}
}
private class StringConcatenationTree extends StandardTree, StringConcatenation {
private class StringConcatenationTree extends StandardPostOrderTree, StringConcatenation {
final override ControlFlowTree getChildElement(int i) { result = this.getString(i) }
final override predicate first(AstNode first) { first(this.getFirstChildElement(), first) }
final override predicate last(AstNode last, Completion c) {
last(this.getLastChildElement(), last, c)
}
}
private class StringlikeLiteralTree extends StandardPostOrderTree, StringlikeLiteral {
@@ -1381,15 +1366,11 @@ module Trees {
}
}
private class TuplePatternTree extends StandardPostOrderTree, TuplePattern {
final override ControlFlowTree getChildElement(int i) { result = this.getElement(i) }
}
private class UndefStmtTree extends StandardPreOrderTree, UndefStmt {
final override ControlFlowTree getChildElement(int i) { result = this.getMethodName(i) }
}
private class WhenTree extends PreOrderTree, WhenExpr {
private class WhenTree extends PreOrderTree, WhenClause {
final override predicate propagatesAbnormal(AstNode child) { child = this.getAPattern() }
final Expr getLastPattern() {

View File

@@ -23,10 +23,10 @@ module SummaryComponent {
predicate content = SC::content/1;
/** Gets a summary component that represents a qualifier. */
SummaryComponent qualifier() { result = argument(-1) }
SummaryComponent qualifier() { result = argument(any(ParameterPosition pos | pos.isSelf())) }
/** Gets a summary component that represents a block argument. */
SummaryComponent block() { result = argument(-2) }
SummaryComponent block() { result = argument(any(ParameterPosition pos | pos.isBlock())) }
/** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = SC::return(any(NormalReturnKind rk)) }
@@ -102,10 +102,10 @@ abstract class SummarizedCallable extends LibraryCallable {
/**
* Holds if values stored inside `content` are cleared on objects passed as
* the `i`th argument to this callable.
* arguments at position `pos` to this callable.
*/
pragma[nomagic]
predicate clearsContent(int i, DataFlow::Content content) { none() }
predicate clearsContent(ParameterPosition pos, DataFlow::Content content) { none() }
}
private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable {
@@ -119,8 +119,8 @@ private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable
sc.propagatesFlow(input, output, preservesValue)
}
final override predicate clearsContent(ParameterPosition i, DataFlow::Content content) {
sc.clearsContent(i, content)
final override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
sc.clearsContent(pos, content)
}
}

View File

@@ -4,6 +4,7 @@ private import DataFlowPrivate
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.ast.internal.Module
private import FlowSummaryImpl as FlowSummaryImpl
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.FlowSummary
newtype TReturnKind =
@@ -230,6 +231,30 @@ private module Cached {
result = yieldCall(call)
)
}
cached
newtype TArgumentPosition =
TSelfArgumentPosition() or
TBlockArgumentPosition() or
TPositionalArgumentPosition(int pos) {
exists(Call c | exists(c.getArgument(pos)))
or
FlowSummaryImplSpecific::ParsePositions::isParsedParameterPosition(_, pos)
} or
TKeywordArgumentPosition(string name) { name = any(KeywordParameter kp).getName() }
cached
newtype TParameterPosition =
TSelfParameterPosition() or
TBlockParameterPosition() or
TPositionalParameterPosition(int pos) {
pos = any(Parameter p).getPosition()
or
pos in [0 .. 10] // TODO: remove once `Argument[_]` summaries are replaced with `Argument[i..]`
or
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentPosition(_, pos)
} or
TKeywordParameterPosition(string name) { name = any(KeywordParameter kp).getName() }
}
import Cached
@@ -400,7 +425,7 @@ private DataFlow::LocalSourceNode trackModule(Module tp, TypeTracker t) {
t.start() and
(
// ConstantReadAccess to Module
resolveScopeExpr(result.asExpr().getExpr()) = tp
resolveConstantReadAccess(result.asExpr().getExpr()) = tp
or
// `self` reference to Module
result = selfInModule(tp)
@@ -458,18 +483,66 @@ predicate exprNodeReturnedFrom(DataFlow::ExprNode e, Callable c) {
)
}
private int parameterPosition() { result in [-2 .. max([any(Parameter p).getPosition(), 10])] }
/** A parameter position. */
class ParameterPosition extends TParameterPosition {
/** Holds if this position represents a `self` parameter. */
predicate isSelf() { this = TSelfParameterPosition() }
/** A parameter position represented by an integer. */
class ParameterPosition extends int {
ParameterPosition() { this = parameterPosition() }
/** Holds if this position represents a block parameter. */
predicate isBlock() { this = TBlockParameterPosition() }
/** Holds if this position represents a positional parameter at position `pos`. */
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
/** Holds if this position represents a keyword parameter named `name`. */
predicate isKeyword(string name) { this = TKeywordParameterPosition(name) }
/** Gets a textual representation of this position. */
string toString() {
this.isSelf() and result = "self"
or
this.isBlock() and result = "block"
or
exists(int pos | this.isPositional(pos) and result = "position " + pos)
or
exists(string name | this.isKeyword(name) and result = "keyword " + name)
}
}
/** An argument position represented by an integer. */
class ArgumentPosition extends int {
ArgumentPosition() { this = parameterPosition() }
/** An argument position. */
class ArgumentPosition extends TArgumentPosition {
/** Holds if this position represents a `self` argument. */
predicate isSelf() { this = TSelfArgumentPosition() }
/** Holds if this position represents a block argument. */
predicate isBlock() { this = TBlockArgumentPosition() }
/** Holds if this position represents a positional argument at position `pos`. */
predicate isPositional(int pos) { this = TPositionalArgumentPosition(pos) }
/** Holds if this position represents a keyword argument named `name`. */
predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) }
/** Gets a textual representation of this position. */
string toString() {
this.isSelf() and result = "self"
or
this.isBlock() and result = "block"
or
exists(int pos | this.isPositional(pos) and result = "position " + pos)
or
exists(string name | this.isKeyword(name) and result = "keyword " + name)
}
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
pragma[inline]
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
ppos.isSelf() and apos.isSelf()
or
ppos.isBlock() and apos.isBlock()
or
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
or
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
}

View File

@@ -15,11 +15,23 @@ module Consistency {
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
predicate uniqueEnclosingCallableExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
predicate uniqueNodeLocationExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
predicate missingLocationExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
predicate reverseReadExclude(Node n) { none() }
}
private class RelevantNode extends Node {
@@ -46,6 +58,7 @@ module Consistency {
n instanceof RelevantNode and
c = count(nodeGetEnclosingCallable(n)) and
c != 1 and
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
msg = "Node should have one enclosing callable but has " + c + "."
)
}
@@ -66,6 +79,7 @@ module Consistency {
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
) and
c != 1 and
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
msg = "Node should have one location but has " + c + "."
)
}
@@ -76,7 +90,8 @@ module Consistency {
strictcount(Node n |
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
) and
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
) and
msg = "Nodes without location: " + c
)
@@ -172,6 +187,7 @@ module Consistency {
query predicate reverseRead(Node n, string msg) {
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
msg = "Origin of readStep is missing a PostUpdateNode."
}

View File

@@ -126,7 +126,16 @@ module LocalFlow {
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalExprCfgNode).getBranch(_)
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::CaseExprCfgNode).getBranch(_)
exists(CfgNode n, Stmt stmt, CaseExpr c |
c = nodeTo.asExpr().getExpr() and
n = nodeFrom.asExpr() and
n = nodeTo.asExpr().getAPredecessor() and
stmt = n.getNode()
|
stmt = c.getElseBranch() or
stmt = c.getABranch().(InClause).getBody() or
stmt = c.getABranch().(WhenClause).getBody()
)
or
exists(CfgNodes::ExprCfgNode exprTo, ReturningStatementNode n |
nodeFrom = n and
@@ -152,17 +161,29 @@ module LocalFlow {
/** An argument of a call (including qualifier arguments, excluding block arguments). */
private class Argument extends CfgNodes::ExprCfgNode {
private CfgNodes::ExprNodes::CallCfgNode call;
private int arg;
private ArgumentPosition arg;
Argument() {
this = call.getArgument(arg) and
not this.getExpr() instanceof BlockArgument
exists(int i |
this = call.getArgument(i) and
not this.getExpr() instanceof BlockArgument and
not exists(this.getExpr().(Pair).getKey().getValueText()) and
arg.isPositional(i)
)
or
this = call.getReceiver() and arg = -1
exists(CfgNodes::ExprNodes::PairCfgNode p |
p = call.getArgument(_) and
this = p.getValue() and
arg.isKeyword(p.getKey().getValueText())
)
or
this = call.getReceiver() and arg.isSelf()
}
/** Holds if this expression is the `i`th argument of `c`. */
predicate isArgumentOf(CfgNodes::ExprNodes::CallCfgNode c, int i) { c = call and i = arg }
predicate isArgumentOf(CfgNodes::ExprNodes::CallCfgNode c, ArgumentPosition pos) {
c = call and pos = arg
}
}
/** A collection of cached types and predicates to be evaluated in the same stage. */
@@ -179,7 +200,11 @@ private module Cached {
)
} or
TSsaDefinitionNode(Ssa::Definition def) or
TNormalParameterNode(Parameter p) { not p instanceof BlockParameter } or
TNormalParameterNode(Parameter p) {
p instanceof SimpleParameter or
p instanceof OptionalParameter or
p instanceof KeywordParameter
} or
TSelfParameterNode(MethodBase m) or
TBlockParameterNode(MethodBase m) or
TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { n instanceof Argument } or
@@ -189,8 +214,8 @@ private module Cached {
) {
FlowSummaryImpl::Private::summaryNodeRange(c, state)
} or
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, int i) {
FlowSummaryImpl::Private::summaryParameterNodeRange(c, i)
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) {
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
}
class TParameterNode =
@@ -331,10 +356,10 @@ private module ParameterNodes {
abstract class ParameterNodeImpl extends NodeImpl {
abstract Parameter getParameter();
abstract predicate isSourceParameterOf(Callable c, int i);
abstract predicate isSourceParameterOf(Callable c, ParameterPosition pos);
predicate isParameterOf(DataFlowCallable c, int i) {
this.isSourceParameterOf(c.asCallable(), i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.isSourceParameterOf(c.asCallable(), pos)
}
}
@@ -349,10 +374,18 @@ private module ParameterNodes {
override Parameter getParameter() { result = parameter }
override predicate isSourceParameterOf(Callable c, int i) { c.getParameter(i) = parameter }
override predicate isParameterOf(DataFlowCallable c, int i) {
this.isSourceParameterOf(c.asCallable(), i)
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
exists(int i | pos.isPositional(i) and c.getParameter(i) = parameter |
parameter instanceof SimpleParameter
or
parameter instanceof OptionalParameter
)
or
parameter =
any(KeywordParameter kp |
c.getAParameter() = kp and
pos.isKeyword(kp.getName())
)
}
override CfgScope getCfgScope() { result = parameter.getCallable() }
@@ -375,10 +408,8 @@ private module ParameterNodes {
override Parameter getParameter() { none() }
override predicate isSourceParameterOf(Callable c, int i) { method = c and i = -1 }
override predicate isParameterOf(DataFlowCallable c, int i) {
this.isSourceParameterOf(c.asCallable(), i)
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
method = c and pos.isSelf()
}
override CfgScope getCfgScope() { result = method }
@@ -403,10 +434,8 @@ private module ParameterNodes {
result = method.getAParameter() and result instanceof BlockParameter
}
override predicate isSourceParameterOf(Callable c, int i) { c = method and i = -2 }
override predicate isParameterOf(DataFlowCallable c, int i) {
this.isSourceParameterOf(c.asCallable(), i)
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
c = method and pos.isBlock()
}
override CfgScope getCfgScope() { result = method }
@@ -427,15 +456,17 @@ private module ParameterNodes {
/** A parameter for a library callable with a flow summary. */
class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode {
private FlowSummaryImpl::Public::SummarizedCallable sc;
private int pos;
private ParameterPosition pos_;
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos) }
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos_) }
override Parameter getParameter() { none() }
override predicate isSourceParameterOf(Callable c, int i) { none() }
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) { none() }
override predicate isParameterOf(DataFlowCallable c, int i) { sc = c and i = pos }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
sc = c and pos = pos_
}
override CfgScope getCfgScope() { none() }
@@ -443,7 +474,7 @@ private module ParameterNodes {
override EmptyLocation getLocationImpl() { any() }
override string toStringImpl() { result = "parameter " + pos + " of " + sc }
override string toStringImpl() { result = "parameter " + pos_ + " of " + sc }
}
}
@@ -468,9 +499,9 @@ class SummaryNode extends NodeImpl, TSummaryNode {
/** A data-flow node that represents a call argument. */
abstract class ArgumentNode extends Node {
/** Holds if this argument occurs at the given position in the given call. */
abstract predicate argumentOf(DataFlowCall call, int pos);
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
abstract predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos);
abstract predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos);
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
@@ -483,18 +514,18 @@ private module ArgumentNodes {
ExplicitArgumentNode() { this.asExpr() = arg }
override predicate argumentOf(DataFlowCall call, int pos) {
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
this.sourceArgumentOf(call.asCall(), pos)
}
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos) {
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
arg.isArgumentOf(call, pos)
}
}
/** A data-flow node that represents the `self` argument of a call. */
class SelfArgumentNode extends ExplicitArgumentNode {
SelfArgumentNode() { arg.isArgumentOf(_, -1) }
SelfArgumentNode() { arg.isArgumentOf(_, any(ArgumentPosition pos | pos.isSelf())) }
}
/** A data-flow node that represents a block argument. */
@@ -504,12 +535,12 @@ private module ArgumentNodes {
exists(CfgNodes::ExprNodes::CallCfgNode c | c.getBlock() = this.asExpr())
}
override predicate argumentOf(DataFlowCall call, int pos) {
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
this.sourceArgumentOf(call.asCall(), pos)
}
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos) {
pos = -2 and
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
pos.isBlock() and
(
this.asExpr() = call.getBlock()
or
@@ -525,9 +556,11 @@ private module ArgumentNodes {
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos) { none() }
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
none()
}
override predicate argumentOf(DataFlowCall call, int pos) {
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
}
}
@@ -838,7 +871,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
)
or
receiver = call.(SummaryCall).getReceiver() and
if receiver.(ParameterNodeImpl).isParameterOf(_, -2)
if receiver.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pos | pos.isBlock()))
then kind = TYieldCallKind()
else kind = TLambdaCallKind()
}

View File

@@ -61,6 +61,12 @@ class CallNode extends LocalSourceNode {
/** Gets the name of the the method called by the method call (if any) corresponding to this data-flow node */
string getMethodName() { result = node.getExpr().(MethodCall).getMethodName() }
/** Gets the number of arguments of this call. */
int getNumberOfArguments() { result = node.getNumberOfArguments() }
/** Gets the block of this call. */
Node getBlock() { result.asExpr() = node.getBlock() }
}
/**

View File

@@ -736,10 +736,17 @@ module Private {
}
pragma[nomagic]
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
exists(DataFlowCall call, ParameterPosition ppos, SummarizedCallable sc |
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
exists(ParameterPosition ppos, SummarizedCallable sc |
argumentPositionMatch(call, arg, ppos) and
viableParam(call, sc, ppos, result) and
viableParam(call, sc, ppos, result)
)
}
pragma[nomagic]
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
exists(DataFlowCall call |
result = summaryArgParam0(call, arg) and
out = rk.getAnOutNode(call)
)
}

View File

@@ -12,7 +12,7 @@ private import FlowSummaryImpl::Public
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
/** Gets the parameter position of the instance parameter. */
int instanceParameterPosition() { none() } // disables implicit summary flow to `self` for callbacks
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `self` for callbacks
/** Gets the synthesized summary data-flow node for the given values. */
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
@@ -31,8 +31,8 @@ DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { any() }
* Gets the type of the `i`th parameter in a synthesized call that targets a
* callback of type `t`.
*/
bindingset[t, i]
DataFlowType getCallbackParameterType(DataFlowType t, int i) { any() }
bindingset[t, pos]
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) { any() }
/**
* Gets the return type of kind `rk` in a synthesized call that targets a
@@ -63,12 +63,13 @@ SummaryComponent interpretComponentSpecific(string c) {
result = FlowSummary::SummaryComponent::block()
or
c = "Argument[_]" and
result = FlowSummary::SummaryComponent::argument(any(int i | i >= 0))
result = FlowSummary::SummaryComponent::argument(any(ParameterPosition pos | pos.isPositional(_)))
}
/** Gets the textual representation of a summary component in the format used for flow summaries. */
string getComponentSpecificCsv(SummaryComponent sc) {
sc = TArgumentSummaryComponent(-2) and result = "BlockArgument"
sc = TArgumentSummaryComponent(any(ParameterPosition pos | pos.isBlock())) and
result = "BlockArgument"
}
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
@@ -127,21 +128,57 @@ private module UnusedSourceSinkInterpretation {
import UnusedSourceSinkInterpretation
bindingset[s]
private int parsePosition(string s) {
result = s.regexpCapture("([-0-9]+)", 1).toInt()
or
exists(int n1, int n2 |
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
result in [n1 .. n2]
)
module ParsePositions {
private import FlowSummaryImpl
private predicate isParamBody(string body) {
exists(string c |
Private::External::specSplit(_, c, _) and
body = c.regexpCapture("Parameter\\[([^\\]]*)\\]", 1)
)
}
private predicate isArgBody(string body) {
exists(string c |
Private::External::specSplit(_, c, _) and
body = c.regexpCapture("Argument\\[([^\\]]*)\\]", 1)
)
}
bindingset[s]
private int parsePosition(string s) {
result = s.regexpCapture("([-0-9]+)", 1).toInt()
or
exists(int n1, int n2 |
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
result in [n1 .. n2]
)
}
predicate isParsedParameterPosition(string c, int i) {
isParamBody(c) and
i = parsePosition(c)
}
predicate isParsedArgumentPosition(string c, int i) {
isArgBody(c) and
i = parsePosition(c)
}
}
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
bindingset[s]
ArgumentPosition parseParamBody(string s) { result = parsePosition(s) }
ArgumentPosition parseParamBody(string s) {
exists(int i |
ParsePositions::isParsedParameterPosition(s, i) and
result.isPositional(i)
)
}
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
bindingset[s]
ParameterPosition parseArgBody(string s) { result = parsePosition(s) }
ParameterPosition parseArgBody(string s) {
exists(int i |
ParsePositions::isParsedArgumentPosition(s, i) and
result.isPositional(i)
)
}

View File

@@ -43,7 +43,7 @@ class ActionControllerControllerClass extends ClassDeclaration {
or
// class BarController < FooController
exists(ActionControllerControllerClass other |
other.getModule() = resolveScopeExpr(this.getSuperclassExpr())
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
)
}
@@ -54,13 +54,13 @@ class ActionControllerControllerClass extends ClassDeclaration {
}
/**
* An instance method defined within an `ActionController` controller class.
* A public instance method defined within an `ActionController` controller class.
* This may be the target of a route handler, if such a route is defined.
*/
class ActionControllerActionMethod extends Method, HTTP::Server::RequestHandler::Range {
private ActionControllerControllerClass controllerClass;
ActionControllerActionMethod() { this = controllerClass.getAMethod() }
ActionControllerActionMethod() { this = controllerClass.getAMethod() and not this.isPrivate() }
/**
* Establishes a mapping between a method within the file

View File

@@ -59,7 +59,7 @@ class ActiveRecordModelClass extends ClassDeclaration {
or
// class Bar < Foo
exists(ActiveRecordModelClass other |
other.getModule() = resolveScopeExpr(this.getSuperclassExpr())
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
)
}
@@ -101,7 +101,7 @@ class ActiveRecordModelClassMethodCall extends MethodCall {
ActiveRecordModelClassMethodCall() {
// e.g. Foo.where(...)
recvCls.getModule() = resolveScopeExpr(this.getReceiver())
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
or
// e.g. Foo.joins(:bars).where(...)
recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass()
@@ -278,7 +278,7 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
ActiveRecordModelFinderCall() {
call = this.asExpr().getExpr() and
recv = getUltimateReceiver(call) and
resolveConstant(recv) = cls.getQualifiedName() and
resolveConstant(recv) = cls.getAQualifiedName() and
call.getMethodName() = finderMethodName()
}

View File

@@ -29,7 +29,9 @@ private class RailtieClassAccess extends ConstantReadAccess {
private class RailtieClass extends ClassDeclaration {
RailtieClass() {
this.getSuperclassExpr() instanceof RailtieClassAccess or
exists(RailtieClass other | other.getModule() = resolveScopeExpr(this.getSuperclassExpr()))
exists(RailtieClass other |
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
)
}
}
@@ -40,7 +42,7 @@ private DataFlow::CallNode getAConfigureCallNode() {
// `Rails::Application.configure`
exists(ConstantReadAccess read, RailtieClass cls |
read = result.getReceiver().asExpr().getExpr() and
resolveScopeExpr(read) = cls.getModule() and
resolveConstantReadAccess(read) = cls.getModule() and
result.asExpr().getExpr().(MethodCall).getMethodName() = "configure"
)
}

View File

@@ -3,6 +3,8 @@ private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
private import codeql.ruby.ApiGraphs
private import codeql.ruby.dataflow.FlowSummary
private import codeql.ruby.dataflow.internal.DataFlowDispatch
private import codeql.ruby.CFG
/**
* The `Kernel` module is included by the `Object` class, so its methods are available
@@ -26,8 +28,6 @@ class KernelMethodCall extends DataFlow::CallNode {
)
)
}
int getNumberOfArguments() { result = methodCall.getNumberOfArguments() }
}
/**
@@ -349,3 +349,103 @@ class RegexpEscapeSummary extends SummarizedCallable {
preservesValue = false
}
}
/** A reference to a `Logger` instance */
private DataFlow::Node loggerInstance() {
result = API::getTopLevelMember("Logger").getAnInstantiation()
or
exists(DataFlow::Node inst |
inst = loggerInstance() and
inst.(DataFlow::LocalSourceNode).flowsTo(result)
)
or
// Assume that a variable assigned as a `Logger` instance is always a
// `Logger` instance. This covers class and instance variables where we can't
// necessarily trace a dataflow path from assignment to use.
exists(Variable v, Assignment a |
a.getLeftOperand().getAVariable() = v and
a.getRightOperand() = loggerInstance().asExpr().getExpr() and
result.asExpr().getExpr().(VariableReadAccess).getVariable() = v
)
}
/**
* A call to a `Logger` instance method that causes a message to be logged.
*/
abstract class LoggerLoggingCall extends Logging::Range, DataFlow::CallNode {
LoggerLoggingCall() { this.getReceiver() = loggerInstance() }
}
/**
* A call to `Logger#add` or its alias `Logger#log`.
*/
private class LoggerAddCall extends LoggerLoggingCall {
LoggerAddCall() { this.getMethodName() = ["add", "log"] }
override DataFlow::Node getAnInput() {
// Both the message and the progname are form part of the log output:
// Logger#add(severity, message) / Logger#add(severity, message, progname)
result = this.getArgument(1)
or
result = this.getArgument(2)
or
// a return value from the block in Logger#add(severity) <block> or in
// Logger#add(severity, nil, progname) <block>
(
this.getNumberOfArguments() = 1
or
// TODO: this could track the value of the `message` argument to make
// this check more accurate
this.getArgument(1).asExpr().getExpr() instanceof NilLiteral
) and
exprNodeReturnedFrom(result, this.getBlock().asExpr().getExpr())
}
}
/**
* A call to `Logger#<<`.
*/
private class LoggerPushCall extends LoggerLoggingCall {
LoggerPushCall() { this.getMethodName() = "<<" }
override DataFlow::Node getAnInput() {
// Logger#<<(msg)
result = this.getArgument(0)
}
}
/**
* A call to a `Logger` method that logs at a preset severity level.
*
* Specifically, these methods are `debug`, `error`, `fatal`, `info`,
* `unknown`, and `warn`.
*/
private class LoggerInfoStyleCall extends LoggerLoggingCall {
LoggerInfoStyleCall() {
this.getMethodName() = ["debug", "error", "fatal", "info", "unknown", "warn"]
}
override DataFlow::Node getAnInput() {
// `msg` from `Logger#info(msg)`,
// or `progname` from `Logger#info(progname) <block>`
result = this.getArgument(0)
or
// a return value from the block in `Logger#info(progname) <block>`
exprNodeReturnedFrom(result, this.getBlock().asExpr().getExpr())
}
}
/**
* A call to `Logger#progname=`. This sets a default progname.
* This call does not log anything directly, but the assigned value can appear
* in future log messages that do not specify a `progname` argument.
*/
private class LoggerSetPrognameCall extends LoggerLoggingCall {
LoggerSetPrognameCall() { this.getMethodName() = "progname=" }
override DataFlow::Node getAnInput() {
exists(CfgNodes::ExprNodes::AssignExprCfgNode a | this.getArgument(0).asExpr() = a |
result.asExpr() = a.getRhs()
)
}
}

View File

@@ -0,0 +1,61 @@
/**
* Provides default sources, sinks, and sanitizers for reasoning about bypass of
* sensitive action guards, as well as extension points for adding your own.
*/
private import codeql.ruby.CFG
private import codeql.ruby.DataFlow
private import codeql.ruby.controlflow.BasicBlocks
private import codeql.ruby.dataflow.RemoteFlowSources
private import codeql.ruby.security.SensitiveActions
/**
* Provides default sources, sinks, and sanitizers for reasoning about bypass of
* sensitive action guards, as well as extension points for adding your own.
*/
module ConditionalBypass {
/**
* A data flow source for bypass of sensitive action guards.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for bypass of sensitive action guards.
*/
abstract class Sink extends DataFlow::Node {
/**
* Gets the guarded sensitive action.
*/
abstract SensitiveAction getAction();
}
/**
* A sanitizer for bypass of sensitive action guards.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A source of remote user input, considered as a flow source for bypass of
* sensitive action guards.
*/
class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/**
* A conditional that guards a sensitive action, e.g. `ok` in `if (ok) login()`.
*/
class SensitiveActionGuardConditional extends Sink {
SensitiveAction action;
SensitiveActionGuardConditional() {
exists(ConditionBlock cb, BasicBlock controlled |
cb.controls(controlled, _) and
controlled.getANode() = action.asExpr() and
cb.getLastNode() = this.asExpr()
)
}
override SensitiveAction getAction() { result = action }
}
}

View File

@@ -0,0 +1,28 @@
/**
* Provides a taint tracking configuration for reasoning about bypass of sensitive action guards.
*
* Note, for performance reasons: only import this file if
* `ConditionalBypass::Configuration` is needed, otherwise
* `ConditionalBypassCustomizations` should be imported instead.
*/
private import codeql.ruby.DataFlow
private import codeql.ruby.TaintTracking
private import codeql.ruby.security.SensitiveActions
import ConditionalBypassCustomizations::ConditionalBypass
/**
* A taint tracking configuration for bypass of sensitive action guards.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "ConditionalBypass" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) {
super.isSanitizer(node) or
node instanceof Sanitizer
}
}

View File

@@ -0,0 +1,98 @@
/**
* Provides classes modeling cryptographic algorithms, separated into strong and weak variants.
*
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
*/
private import internal.CryptoAlgorithmNames
/**
* A cryptographic algorithm.
*/
private newtype TCryptographicAlgorithm =
MkHashingAlgorithm(string name, boolean isWeak) {
isStrongHashingAlgorithm(name) and isWeak = false
or
isWeakHashingAlgorithm(name) and isWeak = true
} or
MkEncryptionAlgorithm(string name, boolean isWeak) {
isStrongEncryptionAlgorithm(name) and isWeak = false
or
isWeakEncryptionAlgorithm(name) and isWeak = true
} or
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
isStrongPasswordHashingAlgorithm(name) and isWeak = false
or
isWeakPasswordHashingAlgorithm(name) and isWeak = true
}
/**
* A cryptographic algorithm.
*/
abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
/** Gets a textual representation of this element. */
string toString() { result = getName() }
/**
* Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores).
*/
abstract string getName();
/**
* Holds if the name of this algorithm matches `name` modulo case,
* white space, dashes, underscores, and anything after a dash in the name
* (to ignore modes of operation, such as CBC or ECB).
*/
bindingset[name]
predicate matchesName(string name) {
[name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)]
.regexpReplaceAll("[-_ ]", "") = getName()
}
/**
* Holds if this algorithm is weak.
*/
abstract predicate isWeak();
}
/**
* A hashing algorithm such as `MD5` or `SHA512`.
*/
class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
string name;
boolean isWeak;
HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
override string getName() { result = name }
override predicate isWeak() { isWeak = true }
}
/**
* An encryption algorithm such as `DES` or `AES512`.
*/
class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
string name;
boolean isWeak;
EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
override string getName() { result = name }
override predicate isWeak() { isWeak = true }
}
/**
* A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
*/
class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
string name;
boolean isWeak;
PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
override string getName() { result = name }
override predicate isWeak() { isWeak = true }
}

View File

@@ -0,0 +1,311 @@
/**
* Provides classes modeling parts of the Ruby `OpenSSL` library, which wraps
* an underlying OpenSSL or LibreSSL C library.
*/
private import internal.CryptoAlgorithmNames
bindingset[algorithmString]
private string algorithmRegex(string algorithmString) {
// Algorithms usually appear in names surrounded by characters that are not
// alphabetical characters in the same case. This handles the upper and lower
// case cases.
result =
"((^|.*[^A-Z])(" + algorithmString + ")([^A-Z].*|$))" +
// or...
"|" +
// For lowercase, we want to be careful to avoid being confused by camelCase
// hence we require two preceding uppercase letters to be sure of a case switch,
// or a preceding non-alphabetic character
"((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))"
}
private string rankedInsecureAlgorithm(int i) {
// In this case we know these are being used for encryption, so we want to match
// weak hash algorithms and block modes as well.
result =
rank[i](string s |
isWeakEncryptionAlgorithm(s) or isWeakHashingAlgorithm(s) or isWeakBlockMode(s)
)
}
private string insecureAlgorithmString(int i) {
i = 1 and result = rankedInsecureAlgorithm(i)
or
result = rankedInsecureAlgorithm(i) + "|" + insecureAlgorithmString(i - 1)
}
/**
* Gets the regular expression used for matching strings that look like they
* contain an algorithm that is known to be insecure.
*/
private string getInsecureAlgorithmRegex() {
result = algorithmRegex(insecureAlgorithmString(max(int i | exists(rankedInsecureAlgorithm(i)))))
}
private string rankedSecureAlgorithm(int i) {
result = rank[i](string s | isStrongEncryptionAlgorithm(s))
}
private string secureAlgorithmString(int i) {
i = 1 and result = rankedSecureAlgorithm(i)
or
result = rankedSecureAlgorithm(i) + "|" + secureAlgorithmString(i - 1)
}
/**
* Gets a regular expression for matching strings that look like they
* contain an algorithm that is known to be secure.
*/
string getSecureAlgorithmRegex() {
result = algorithmRegex(secureAlgorithmString(max(int i | exists(rankedSecureAlgorithm(i)))))
}
/**
* Names of known ciphers supported by the Ruby `OpenSSL` library, and
* classification into strong and weak ciphers. Cipher support in practice
* depends on the underlying `OpenSSL`/`LibreSSL` library.
*/
module Ciphers {
/**
* Holds if `name` is a known `OpenSSL::Cipher`. Supported ciphers depend on the
* version of `OpenSSL` or `LibreSSL` specified when installing the `openssl` gem.
* Ciphers listed here are sourced from OpenSSL 1.1.1 and LibreSSL 3.4.1.
*
* In the general case, a name will include the cipher name, the key length,
* and the block encryption mode.
*
* Note that since the cipher name itself always comes first in these names
* and always uses a "-" to demark to block mode, we can safely uppercase
* these names when checking against an `algorithmRegex`.
*
* See https://ruby-doc.org/stdlib-3.0.1/libdoc/openssl/rdoc/OpenSSL/Cipher.html
*/
predicate isOpenSSLCipher(string name) {
name =
[
"aes-128-cbc", "aes-128-cbc-hmac-sha1", "aes-128-cbc-hmac-sha256", "aes-128-ccm",
"aes-128-cfb", "aes-128-cfb1", "aes-128-cfb8", "aes-128-ctr", "aes-128-ecb", "aes-128-gcm",
"aes-128-ocb", "aes-128-ofb", "aes-128-xts", "aes-192-cbc", "aes-192-ccm", "aes-192-cfb",
"aes-192-cfb1", "aes-192-cfb8", "aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-ocb",
"aes-192-ofb", "aes-256-cbc", "aes-256-cbc-hmac-sha1", "aes-256-cbc-hmac-sha256",
"aes-256-ccm", "aes-256-cfb", "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr", "aes-256-ecb",
"aes-256-gcm", "aes-256-ocb", "aes-256-ofb", "aes-256-xts", "aes128", "aes192", "aes256",
"aria-128-cbc", "aria-128-ccm", "aria-128-cfb", "aria-128-cfb1", "aria-128-cfb8",
"aria-128-ctr", "aria-128-ecb", "aria-128-gcm", "aria-128-ofb", "aria-192-cbc",
"aria-192-ccm", "aria-192-cfb", "aria-192-cfb1", "aria-192-cfb8", "aria-192-ctr",
"aria-192-ecb", "aria-192-gcm", "aria-192-ofb", "aria-256-cbc", "aria-256-ccm",
"aria-256-cfb", "aria-256-cfb1", "aria-256-cfb8", "aria-256-ctr", "aria-256-ecb",
"aria-256-gcm", "aria-256-ofb", "aria128", "aria192", "aria256", "bf", "bf-cbc", "bf-cfb",
"bf-ecb", "bf-ofb", "blowfish", "camellia-128-cbc", "camellia-128-cfb", "camellia-128-cfb1",
"camellia-128-cfb8", "camellia-128-ctr", "camellia-128-ecb", "camellia-128-ofb",
"camellia-192-cbc", "camellia-192-cfb", "camellia-192-cfb1", "camellia-192-cfb8",
"camellia-192-ctr", "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc",
"camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ctr",
"camellia-256-ecb", "camellia-256-ofb", "camellia128", "camellia192", "camellia256", "cast",
"cast-cbc", "cast5-cbc", "cast5-cfb", "cast5-ecb", "cast5-ofb", "chacha20",
"chacha20-poly1305", "des", "des-cbc", "des-cfb", "des-cfb1", "des-cfb8", "des-ecb",
"des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ecb", "des-ede-ofb", "des-ede3",
"des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8", "des-ede3-ecb",
"des-ede3-ofb", "des-ofb", "des3", "desx", "desx-cbc", "id-aes128-CCM", "id-aes128-GCM",
"id-aes192-CCM", "id-aes192-GCM", "id-aes256-CCM", "id-aes256-GCM", "idea", "idea-cbc",
"idea-cfb", "idea-ecb", "idea-ofb", "rc2", "rc2-128", "rc2-40", "rc2-40-cbc", "rc2-64",
"rc2-64-cbc", "rc2-cbc", "rc2-cfb", "rc2-ecb", "rc2-ofb", "rc4", "rc4-40", "rc4-hmac-md5",
"seed", "seed-cbc", "seed-cfb", "seed-ecb", "seed-ofb", "sm4", "sm4-cbc", "sm4-cfb",
"sm4-ctr", "sm4-ecb", "sm4-ofb", "AES-128-CBC", "AES-128-CBC-HMAC-SHA1", "AES-128-CFB",
"AES-128-CFB1", "AES-128-CFB8", "AES-128-CTR", "AES-128-ECB", "AES-128-OFB", "AES-128-XTS",
"AES-192-CBC", "AES-192-CFB", "AES-192-CFB1", "AES-192-CFB8", "AES-192-CTR", "AES-192-ECB",
"AES-192-OFB", "AES-256-CBC", "AES-256-CBC-HMAC-SHA1", "AES-256-CFB", "AES-256-CFB1",
"AES-256-CFB8", "AES-256-CTR", "AES-256-ECB", "AES-256-OFB", "AES-256-XTS", "AES128",
"AES192", "AES256", "BF", "BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB", "CAMELLIA-128-CBC",
"CAMELLIA-128-CFB", "CAMELLIA-128-CFB1", "CAMELLIA-128-CFB8", "CAMELLIA-128-ECB",
"CAMELLIA-128-OFB", "CAMELLIA-192-CBC", "CAMELLIA-192-CFB", "CAMELLIA-192-CFB1",
"CAMELLIA-192-CFB8", "CAMELLIA-192-ECB", "CAMELLIA-192-OFB", "CAMELLIA-256-CBC",
"CAMELLIA-256-CFB", "CAMELLIA-256-CFB1", "CAMELLIA-256-CFB8", "CAMELLIA-256-ECB",
"CAMELLIA-256-OFB", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "CAST", "CAST-cbc",
"CAST5-CBC", "CAST5-CFB", "CAST5-ECB", "CAST5-OFB", "ChaCha", "DES", "DES-CBC", "DES-CFB",
"DES-CFB1", "DES-CFB8", "DES-ECB", "DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-OFB",
"DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-CFB1", "DES-EDE3-CFB8",
"DES-EDE3-OFB", "DES-OFB", "DES3", "DESX", "DESX-CBC", "GOST 28147-89", "IDEA", "IDEA-CBC",
"IDEA-CFB", "IDEA-ECB", "IDEA-OFB", "RC2", "RC2-40-CBC", "RC2-64-CBC", "RC2-CBC", "RC2-CFB",
"RC2-ECB", "RC2-OFB", "RC4", "RC4-40", "RC4-HMAC-MD5", "SM4", "SM4-CBC", "SM4-CFB",
"SM4-CTR", "SM4-ECB", "SM4-OFB", "chacha", "gost89", "gost89-cnt", "gost89-ecb"
]
}
/**
* Gets the canonical cipher name in cases where this isn't simply an
* upcased version of the provided name. This may be because a default block
* mode is appended, or due to some other normalization.
*/
private string getSpecialCanonicalCipherName(string name) {
name = "AES128" and result = "AES-128-CBC"
or
name = "AES192" and result = "AES-192-CBC"
or
name = "AES256" and result = "AES-256-CBC"
or
name = "BF" and result = "BF-CBC"
or
name = "CAMELLIA128" and result = "CAMELLIA-128-CBC"
or
name = "CAMELLIA192" and result = "CAMELLIA-192-CBC"
or
name = "CAMELLIA256" and result = "CAMELLIA-256-CBC"
or
name = "CAST" and result = "CAST5-CBC"
or
name = "CAST-cbc" and result = "CAST5-CBC"
or
name = "ChaCha" and result = "ChaCha"
or
name = "DES" and result = "DES-CBC"
or
name = "DES3" and result = "DES-EDE3-CBC"
or
name = "DESX" and result = "DESX-CBC"
or
name = "GOST 28147-89" and result = "gost89"
or
name = "IDEA" and result = "IDEA-CBC"
or
name = "RC2" and result = "RC2-CBC"
or
name = "SM4" and result = "SM4-CBC"
or
name = "aes-128-ccm" and result = "id-aes128-CCM"
or
name = "aes-128-gcm" and result = "id-aes128-GCM"
or
name = "aes-192-ccm" and result = "id-aes192-CCM"
or
name = "aes-192-gcm" and result = "id-aes192-GCM"
or
name = "aes-256-ccm" and result = "id-aes256-CCM"
or
name = "aes-256-gcm" and result = "id-aes256-GCM"
or
name = "aes128" and result = "AES-128-CBC"
or
name = "aes192" and result = "AES-192-CBC"
or
name = "aes256" and result = "AES-256-CBC"
or
name = "bf" and result = "BF-CBC"
or
name = "blowfish" and result = "BF-CBC"
or
name = "camellia128" and result = "CAMELLIA-128-CBC"
or
name = "camellia192" and result = "CAMELLIA-192-CBC"
or
name = "camellia256" and result = "CAMELLIA-256-CBC"
or
name = "cast" and result = "CAST5-CBC"
or
name = "cast-cbc" and result = "CAST5-CBC"
or
name = "chacha" and result = "ChaCha"
or
name = "des" and result = "DES-CBC"
or
name = "des3" and result = "DES-EDE3-CBC"
or
name = "desx" and result = "DESX-CBC"
or
name = "gost89" and result = "gost89"
or
name = "gost89-cnt" and result = "gost89-cnt"
or
name = "gost89-ecb" and result = "gost89-ecb"
or
name = "id-aes128-CCM" and result = "id-aes128-CCM"
or
name = "id-aes128-GCM" and result = "id-aes128-GCM"
or
name = "id-aes192-CCM" and result = "id-aes192-CCM"
or
name = "id-aes192-GCM" and result = "id-aes192-GCM"
or
name = "id-aes256-CCM" and result = "id-aes256-CCM"
or
name = "id-aes256-GCM" and result = "id-aes256-GCM"
or
name = "idea" and result = "IDEA-CBC"
or
name = "rc2" and result = "RC2-CBC"
or
name = "sm4" and result = "SM4-CBC"
}
/**
* Gets the canonical version of `name`, as reported by `OpenSSL::Cipher#name`.
* No result if `name` is not a known OpenSSL cipher name.
*/
string getCanonicalCipherName(string name) {
isOpenSSLCipher(name) and
(
result = getSpecialCanonicalCipherName(name)
or
not exists(getSpecialCanonicalCipherName(name)) and
result = name.toUpperCase()
)
}
/**
* Holds if `name` is the name of an OpenSSL cipher that is known to be weak.
*/
predicate isWeakOpenSSLCipher(string name) {
isOpenSSLCipher(name) and
name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
}
/**
* Holds if `name` is the name of an OpenSSL cipher that is known to be strong.
*/
predicate isStrongOpenSSLCipher(string name) {
isOpenSSLCipher(name) and
name.toUpperCase().regexpMatch(getSecureAlgorithmRegex()) and
// exclude algorithms that include a weak component
not name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
}
}
private import Ciphers
/**
* An OpenSSL cipher.
*/
private newtype TOpenSSLCipher =
MkOpenSSLCipher(string name, boolean isWeak) {
isStrongOpenSSLCipher(name) and isWeak = false
or
isWeakOpenSSLCipher(name) and isWeak = true
}
/**
* A known OpenSSL cipher. This may include information about the block
* encryption mode, which can affect if the cipher is marked as being weak.
*/
class OpenSSLCipher extends MkOpenSSLCipher {
string name;
boolean isWeak;
OpenSSLCipher() { this = MkOpenSSLCipher(name, isWeak) }
/**
* Gets a name of this cipher.
*/
string getName() { result = name }
/**
* Gets a name of this cipher in canonical form.
*/
string getCanonicalName() { result = getCanonicalCipherName(this.getName()) }
/** Holds if this algorithm is weak. */
predicate isWeak() { isWeak = true }
/** Gets a textual representation of this element. */
string toString() { result = this.getCanonicalName() }
}

View File

@@ -0,0 +1,68 @@
/**
* Provides classes and predicates for identifying sensitive data and methods for security.
*
* 'Sensitive' data in general is anything that should not be sent around in unencrypted form. This
* library tries to guess where sensitive data may either be stored in a variable or produced by a
* method.
*
* In addition, there are methods that ought not to be executed or not in a fashion that the user
* can control. This includes authorization methods such as logins, and sending of data, etc.
*/
private import codeql.ruby.AST
private import codeql.ruby.DataFlow
/**
* A sensitive action, such as transfer of sensitive data.
*/
abstract class SensitiveAction extends DataFlow::Node { }
/** Holds if the return value from call `c` is ignored. */
private predicate callWithIgnoredReturnValue(Call c) {
exists(StmtSequence s, int i |
(
// If the call is a top-level statement within a statement sequence, its
// return value (if any) is unused.
c = s.getStmt(i)
or
// Or if the statement is an if-/unless-modifier expr and the call is its
// branch.
exists(ConditionalExpr cond |
cond = s.getStmt(i) and
c = cond.getBranch(_) and
(cond instanceof IfModifierExpr or cond instanceof UnlessModifierExpr)
)
) and
// But exclude calls that are the last statement, since they are evaluated
// as the overall value of the sequence.
exists(s.getStmt(i + 1))
) and
not c instanceof YieldCall and
// Ignore statements in ERB output directives, which are evaluated.
not exists(ErbOutputDirective d | d.getAChildStmt() = c)
}
/** A call that may perform authorization. */
class AuthorizationCall extends SensitiveAction, DataFlow::CallNode {
AuthorizationCall() {
exists(MethodCall c, string s |
c = this.asExpr().getExpr() and
s = c.getMethodName() // name contains `login` or `auth`, but not as part of `loginfo` or `unauth`;
|
// also exclude `author`
s.regexpMatch("(?i).*(log_?in(?!fo)|(?<!un)auth(?!or\\b)|verify).*") and
// but it does not start with `get` or `set`
not s.regexpMatch("(?i)(get|set).*") and
// Setter calls are unlikely to be sensitive actions.
not c instanceof SetterMethodCall and
(
// Calls that have no return value (or ignore it) are likely to be
// to methods that are actions.
callWithIgnoredReturnValue(c)
or
// Method names ending in `!` are likely to be actions.
s.matches("%!")
)
)
}
}

View File

@@ -227,7 +227,7 @@ private module Shared {
isHelperMethod(helperMethod, name, template) and
isMethodCall(helperMethodCall.getExpr(), name, template) and
helperMethodCall.getArgument(pragma[only_bind_into](argIdx)) = node1.asExpr() and
helperMethod.getParameter(pragma[only_bind_into](argIdx)) = node2.asExpr().getExpr()
helperMethod.getParameter(pragma[only_bind_into](argIdx)) = node2.asParameter()
)
}

View File

@@ -0,0 +1,72 @@
/**
* Names of cryptographic algorithms, separated into strong and weak variants.
*
* The names are normalized: upper-case, no spaces, dashes or underscores.
*
* The names are inspired by the names used in real world crypto libraries.
*
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
*/
/**
* Holds if `name` corresponds to a strong hashing algorithm.
*/
predicate isStrongHashingAlgorithm(string name) {
name =
[
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
"SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512"
]
}
/**
* Holds if `name` corresponds to a weak hashing algorithm.
*/
predicate isWeakHashingAlgorithm(string name) {
name =
[
"HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160",
"RIPEMD320", "SHA0", "SHA1"
]
}
/**
* Holds if `name` corresponds to a strong encryption algorithm.
*/
predicate isStrongEncryptionAlgorithm(string name) {
name =
[
"AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512",
"ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192",
"CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89",
"IDEA", "RABBIT", "RSA", "SEED", "SM4"
]
}
/**
* Holds if `name` corresponds to a weak encryption algorithm.
*/
predicate isWeakEncryptionAlgorithm(string name) {
name =
[
"DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4",
"ARCFOUR", "ARC5", "RC5"
]
}
/**
* Holds if `name` corresponds to a strong password hashing algorithm.
*/
predicate isStrongPasswordHashingAlgorithm(string name) {
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
}
/**
* Holds if `name` corresponds to a weak password hashing algorithm.
*/
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
/**
* Holds if `name` corresponds to a weak block cipher mode of operation.
*/
predicate isWeakBlockMode(string name) { name = "ECB" }

View File

@@ -23,6 +23,28 @@ predicate jumpStep = DataFlowPrivate::jumpStep/2;
*/
string getPossibleContentName() { result = getSetterCallAttributeName(_) }
pragma[noinline]
private predicate argumentPositionMatch(
ExprNodes::CallCfgNode call, DataFlowPrivate::ArgumentNode arg,
DataFlowDispatch::ParameterPosition ppos
) {
exists(DataFlowDispatch::ArgumentPosition apos |
arg.sourceArgumentOf(call, apos) and
DataFlowDispatch::parameterMatch(ppos, apos)
)
}
pragma[noinline]
private predicate viableParam(
ExprNodes::CallCfgNode call, DataFlowPrivate::ParameterNodeImpl p,
DataFlowDispatch::ParameterPosition ppos
) {
exists(CFG::CfgScope callable |
DataFlowDispatch::getTarget(call) = callable and
p.isSourceParameterOf(callable, ppos)
)
}
/**
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
*
@@ -31,10 +53,9 @@ string getPossibleContentName() { result = getSetterCallAttributeName(_) }
* methods is done using API graphs (which uses type tracking).
*/
predicate callStep(Node nodeFrom, Node nodeTo) {
exists(ExprNodes::CallCfgNode call, CFG::CfgScope callable, int i |
DataFlowDispatch::getTarget(call) = callable and
nodeFrom.(DataFlowPrivate::ArgumentNode).sourceArgumentOf(call, i) and
nodeTo.(DataFlowPrivate::ParameterNodeImpl).isSourceParameterOf(callable, i)
exists(ExprNodes::CallCfgNode call, DataFlowDispatch::ParameterPosition pos |
argumentPositionMatch(call, nodeFrom, pos) and
viableParam(call, nodeTo, pos)
)
or
// In normal data-flow, this will be a local flow step. But for type tracking

View File

@@ -0,0 +1,36 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Using user-controlled data in a permissions check may allow a user to gain
unauthorized access to protected functionality or data.
</p>
</overview>
<recommendation>
<p>
When checking whether a user is authorized for a particular activity, do
not use data that is entirely controlled by that user in the permissions
check. If necessary, always validate the input, ideally against a fixed
list of expected values.
</p>
<p>
Similarly, do not decide which permission to check based on user data. In
particular, avoid using computation to decide which permissions to check
for. Use fixed permissions for particular actions, rather than generating
the permission to check for.
</p>
</recommendation>
<example>
<p>
In this example, the controller decided whether or not to authenticate the
user based on the value of a request parameter.
</p>
<sample src="examples/bypass.rb" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,82 @@
/**
* @name User-controlled bypass of security check
* @description Conditions controlled by the user are not suited for making security-related decisions.
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision medium
* @id rb/user-controlled-bypass
* @tags security
* external/cwe/cwe-807
* external/cwe/cwe-290
*/
import ruby
import codeql.ruby.DataFlow
import codeql.ruby.dataflow.internal.DataFlowPublic
import codeql.ruby.security.ConditionalBypassQuery
import codeql.ruby.security.SensitiveActions
import DataFlow::PathGraph
/**
* Holds if the value of `nd` flows into `guard`.
*/
predicate flowsToGuardExpr(DataFlow::Node nd, SensitiveActionGuardConditional guard) {
nd = guard
or
exists(DataFlow::Node succ | localFlowStep(nd, succ) | flowsToGuardExpr(succ, guard))
}
/**
* A comparison that guards a sensitive action, e.g. the comparison in:
* ```rb
* ok = x == y
* if ok
* login
* end
* ```
*/
class SensitiveActionGuardComparison extends ComparisonOperation {
SensitiveActionGuardConditional guard;
SensitiveActionGuardComparison() {
exists(DataFlow::Node node | this = node.asExpr().getExpr() | flowsToGuardExpr(node, guard))
}
/**
* Gets the guard that uses this comparison.
*/
SensitiveActionGuardConditional getGuard() { result = guard }
}
/**
* An intermediary sink to enable reuse of the taint configuration.
* This sink should not be presented to the client of this query.
*/
class SensitiveActionGuardComparisonOperand extends Sink {
SensitiveActionGuardComparison comparison;
SensitiveActionGuardComparisonOperand() { this.asExpr().getExpr() = comparison.getAnOperand() }
override SensitiveAction getAction() { result = comparison.getGuard().getAction() }
}
/**
* Holds if `sink` guards `action`, and `source` taints `sink`.
*
* If flow from `source` taints `sink`, then an attacker can
* control if `action` should be executed or not.
*/
predicate isTaintedGuardForSensitiveAction(
DataFlow::PathNode sink, DataFlow::PathNode source, SensitiveAction action
) {
action = sink.getNode().(Sink).getAction() and
// exclude the intermediary sink
not sink.getNode() instanceof SensitiveActionGuardComparisonOperand and
exists(Configuration cfg | cfg.hasFlowPath(source, sink))
}
from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveAction action
where isTaintedGuardForSensitiveAction(sink, source, action)
select sink.getNode(), source, sink, "This condition guards a sensitive $@, but $@ controls it.",
action, "action", source.getNode(), "a user-provided value"

View File

@@ -0,0 +1,10 @@
class UsersController < ActionController::Base
def example
user = User.find_by(login: params[:login])
if params[:authenticate]
# BAD: decision to take sensitive action based on user-controlled data
log_in user
redirect_to user
end
end
end

View File

@@ -78,7 +78,7 @@ ConstantWriteAccess definitionOf(string fqn) {
fqn = resolveConstant(_) and
result =
min(ConstantWriteAccess w, Location l |
w.getQualifiedName() = fqn and l = w.getLocation()
w.getAQualifiedName() = fqn and l = w.getLocation()
|
w
order by

View File

@@ -170,7 +170,7 @@ calls/calls.rb:
# 106| getStmt: [CaseExpr] case ...
# 106| getValue: [MethodCall] call to foo
# 106| getReceiver: [Self, SelfVariableAccess] self
# 107| getBranch: [WhenExpr] when ...
# 107| getBranch: [WhenClause] when ...
# 107| getPattern: [MethodCall] call to bar
# 107| getReceiver: [Self, SelfVariableAccess] self
# 107| getBody: [StmtSequence] then ...
@@ -179,7 +179,7 @@ calls/calls.rb:
# 110| getStmt: [CaseExpr] case ...
# 110| getValue: [MethodCall] call to foo
# 110| getReceiver: [ConstantReadAccess] X
# 111| getBranch: [WhenExpr] when ...
# 111| getBranch: [WhenClause] when ...
# 111| getPattern: [MethodCall] call to bar
# 111| getReceiver: [ConstantReadAccess] X
# 111| getBody: [StmtSequence] then ...
@@ -559,7 +559,7 @@ calls/calls.rb:
# 315| getArgument: [IntegerLiteral] 0
# 315| getAnOperand/getRightOperand: [IntegerLiteral] 10
# 316| getStmt: [AssignExpr] ... = ...
# 316| getLeftOperand: [TuplePattern] (..., ...)
# 316| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
# 316| getElement: [MethodCall] call to foo
# 316| getReceiver: [Self, SelfVariableAccess] self
# 316| getElement: [MethodCall] call to bar
@@ -574,7 +574,7 @@ calls/calls.rb:
# 316| getElement: [IntegerLiteral] 3
# 316| getElement: [IntegerLiteral] 4
# 317| getStmt: [AssignExpr] ... = ...
# 317| getLeftOperand: [TuplePattern] (..., ...)
# 317| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
# 317| getElement: [LocalVariableAccess] a
# 317| getElement: [ElementReference] ...[...]
# 317| getReceiver: [MethodCall] call to foo
@@ -654,7 +654,7 @@ calls/calls.rb:
# 336| getArgument: [LocalVariableAccess] b
# 336| getArgument: [ForwardedArguments] ...
# 340| getStmt: [ForExpr] for ... in ...
# 340| getPattern: [TuplePattern] (..., ...)
# 340| getPattern: [DestructuredLhsExpr] (..., ...)
# 340| getElement: [LocalVariableAccess] x
# 340| getElement: [LocalVariableAccess] y
# 340| getElement: [LocalVariableAccess] z
@@ -689,11 +689,11 @@ control/cases.rb:
# 5| getAnOperand/getRightOperand: [IntegerLiteral] 0
# 8| getStmt: [CaseExpr] case ...
# 8| getValue: [LocalVariableAccess] a
# 9| getBranch: [WhenExpr] when ...
# 9| getBranch: [WhenClause] when ...
# 9| getPattern: [LocalVariableAccess] b
# 9| getBody: [StmtSequence] then ...
# 10| getStmt: [IntegerLiteral] 100
# 11| getBranch: [WhenExpr] when ...
# 11| getBranch: [WhenClause] when ...
# 11| getPattern: [LocalVariableAccess] c
# 11| getPattern: [LocalVariableAccess] d
# 11| getBody: [StmtSequence] then ...
@@ -701,19 +701,19 @@ control/cases.rb:
# 13| getBranch/getElseBranch: [StmtSequence] else ...
# 14| getStmt: [IntegerLiteral] 300
# 18| getStmt: [CaseExpr] case ...
# 19| getBranch: [WhenExpr] when ...
# 19| getBranch: [WhenClause] when ...
# 19| getPattern: [GTExpr] ... > ...
# 19| getAnOperand/getGreaterOperand/getLeftOperand/getReceiver: [LocalVariableAccess] a
# 19| getAnOperand/getArgument/getLesserOperand/getRightOperand: [LocalVariableAccess] b
# 19| getBody: [StmtSequence] then ...
# 19| getStmt: [IntegerLiteral] 10
# 20| getBranch: [WhenExpr] when ...
# 20| getBranch: [WhenClause] when ...
# 20| getPattern: [EqExpr] ... == ...
# 20| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] a
# 20| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] b
# 20| getBody: [StmtSequence] then ...
# 20| getStmt: [IntegerLiteral] 20
# 21| getBranch: [WhenExpr] when ...
# 21| getBranch: [WhenClause] when ...
# 21| getPattern: [LTExpr] ... < ...
# 21| getAnOperand/getLeftOperand/getLesserOperand/getReceiver: [LocalVariableAccess] a
# 21| getAnOperand/getArgument/getGreaterOperand/getRightOperand: [LocalVariableAccess] b
@@ -1333,24 +1333,76 @@ constants/constants.rb:
# 31| getScopeExpr: [ConstantReadAccess] ModuleA
# 31| getSuperclassExpr: [ConstantReadAccess] ClassA
# 31| getScopeExpr: [ConstantReadAccess] ModuleA
# 34| getStmt: [ModuleDeclaration] ModuleC
# 34| getScopeExpr: [ConstantReadAccess] ModuleA
# 37| getStmt: [AssignExpr] ... = ...
# 37| getAnOperand/getLeftOperand: [ConstantAssignment] MAX_SIZE
# 37| getScopeExpr: [ConstantReadAccess] ModuleB
# 37| getScopeExpr: [ConstantReadAccess] ModuleA
# 37| getAnOperand/getRightOperand: [IntegerLiteral] 1024
# 39| getStmt: [MethodCall] call to puts
# 39| getReceiver: [Self, SelfVariableAccess] self
# 39| getArgument: [ConstantReadAccess] MAX_SIZE
# 32| getStmt: [AssignExpr] ... = ...
# 32| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_TWO
# 32| getAnOperand/getRightOperand: [IntegerLiteral] 42
# 35| getStmt: [ModuleDeclaration] ModuleC
# 35| getScopeExpr: [ConstantReadAccess] ModuleA
# 36| getStmt: [AssignExpr] ... = ...
# 36| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_THREE
# 36| getAnOperand/getRightOperand: [IntegerLiteral] 43
# 39| getStmt: [AssignExpr] ... = ...
# 39| getAnOperand/getLeftOperand: [ConstantAssignment] MAX_SIZE
# 39| getScopeExpr: [ConstantReadAccess] ModuleB
# 39| getScopeExpr: [ConstantReadAccess] ModuleA
# 39| getAnOperand/getRightOperand: [IntegerLiteral] 1024
# 41| getStmt: [MethodCall] call to puts
# 41| getReceiver: [Self, SelfVariableAccess] self
# 41| getArgument: [ConstantReadAccess] GREETING
# 42| getStmt: [MethodCall] call to puts
# 42| getReceiver: [Self, SelfVariableAccess] self
# 42| getArgument: [ConstantReadAccess] GREETING
# 41| getArgument: [ConstantReadAccess] MAX_SIZE
# 41| getScopeExpr: [ConstantReadAccess] ModuleB
# 41| getScopeExpr: [ConstantReadAccess] ModuleA
# 43| getStmt: [MethodCall] call to puts
# 43| getReceiver: [Self, SelfVariableAccess] self
# 43| getArgument: [ConstantReadAccess] GREETING
# 44| getStmt: [MethodCall] call to puts
# 44| getReceiver: [Self, SelfVariableAccess] self
# 44| getArgument: [ConstantReadAccess] GREETING
# 46| getStmt: [ModuleDeclaration] ModuleB
# 46| getScopeExpr: [ConstantReadAccess] ModuleA
# 47| getStmt: [ClassDeclaration] ClassB
# 47| getSuperclassExpr: [ConstantReadAccess] Base
# 48| getStmt: [AssignExpr] ... = ...
# 48| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_ONE
# 48| getAnOperand/getRightOperand: [IntegerLiteral] 41
# 52| getStmt: [ModuleDeclaration] ModuleA
# 53| getStmt: [AssignExpr] ... = ...
# 53| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_FOUR
# 53| getAnOperand/getRightOperand: [StringLiteral] "fourty-four"
# 53| getComponent: [StringTextComponent] fourty-four
# 54| getStmt: [ClassDeclaration] ClassB
# 54| getScopeExpr: [ConstantReadAccess] ModuleB
# 54| getSuperclassExpr: [ConstantReadAccess] Base
# 55| getStmt: [AssignExpr] ... = ...
# 55| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_four
# 55| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_FOUR
# 56| getStmt: [AssignExpr] ... = ...
# 56| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_FOUR
# 56| getAnOperand/getRightOperand: [IntegerLiteral] 44
# 57| getStmt: [AssignExpr] ... = ...
# 57| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_four
# 57| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_FOUR
# 61| getStmt: [ModuleDeclaration] Mod1
# 62| getStmt: [ModuleDeclaration] Mod3
# 63| getStmt: [AssignExpr] ... = ...
# 63| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_FIVE
# 63| getAnOperand/getRightOperand: [IntegerLiteral] 45
# 65| getStmt: [AssignExpr] ... = ...
# 65| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_five
# 65| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_FIVE
# 65| getScopeExpr: [ConstantReadAccess] Mod3
# 68| getStmt: [ModuleDeclaration] Mod4
# 69| getStmt: [MethodCall] call to include
# 69| getReceiver: [Self, SelfVariableAccess] self
# 69| getArgument: [ConstantReadAccess] Mod1
# 70| getStmt: [ModuleDeclaration] Mod5
# 70| getScopeExpr: [ConstantReadAccess] Mod3
# 71| getStmt: [AssignExpr] ... = ...
# 71| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_SIX
# 71| getAnOperand/getRightOperand: [IntegerLiteral] 46
# 73| getStmt: [AssignExpr] ... = ...
# 73| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_six
# 73| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_SIX
# 73| getScopeExpr: [ConstantReadAccess] Mod3
literals/literals.rb:
# 1| [Toplevel] literals.rb
# 2| getStmt: [NilLiteral] nil
@@ -1845,7 +1897,7 @@ control/loops.rb:
# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 18| getAnOperand/getRightOperand: [LocalVariableAccess] n
# 22| getStmt: [ForExpr] for ... in ...
# 22| getPattern: [TuplePattern] (..., ...)
# 22| getPattern: [DestructuredLhsExpr] (..., ...)
# 22| getElement: [LocalVariableAccess] key
# 22| getElement: [LocalVariableAccess] value
# 22| getValue: [HashLiteral] {...}
@@ -1863,7 +1915,7 @@ control/loops.rb:
# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 24| getAnOperand/getRightOperand: [LocalVariableAccess] value
# 28| getStmt: [ForExpr] for ... in ...
# 28| getPattern: [TuplePattern] (..., ...)
# 28| getPattern: [DestructuredLhsExpr] (..., ...)
# 28| getElement: [LocalVariableAccess] key
# 28| getElement: [LocalVariableAccess] value
# 28| getValue: [HashLiteral] {...}
@@ -2367,7 +2419,7 @@ params/params.rb:
# 14| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 14| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] bar
# 17| getStmt: [Method] destructured_method_param
# 17| getParameter: [TuplePatternParameter] (..., ...)
# 17| getParameter: [DestructuredParameter] (..., ...)
# 17| getElement: [LocalVariableAccess] a
# 17| getElement: [LocalVariableAccess] b
# 17| getElement: [LocalVariableAccess] c
@@ -2377,7 +2429,7 @@ params/params.rb:
# 22| getStmt: [MethodCall] call to each
# 22| getReceiver: [LocalVariableAccess] array
# 22| getBlock: [BraceBlock] { ... }
# 22| getParameter: [TuplePatternParameter] (..., ...)
# 22| getParameter: [DestructuredParameter] (..., ...)
# 22| getElement: [LocalVariableAccess] a
# 22| getElement: [LocalVariableAccess] b
# 22| getStmt: [MethodCall] call to puts
@@ -2388,10 +2440,10 @@ params/params.rb:
# 25| getStmt: [AssignExpr] ... = ...
# 25| getAnOperand/getLeftOperand: [LocalVariableAccess] sum_four_values
# 25| getAnOperand/getRightOperand: [Lambda] -> { ... }
# 25| getParameter: [TuplePatternParameter] (..., ...)
# 25| getParameter: [DestructuredParameter] (..., ...)
# 25| getElement: [LocalVariableAccess] first
# 25| getElement: [LocalVariableAccess] second
# 25| getParameter: [TuplePatternParameter] (..., ...)
# 25| getParameter: [DestructuredParameter] (..., ...)
# 25| getElement: [LocalVariableAccess] third
# 25| getElement: [LocalVariableAccess] fourth
# 26| getStmt: [AddExpr] ... + ...

View File

@@ -245,7 +245,7 @@ calls/calls.rb:
# 340| getAnOperand/getRightOperand: [MethodCall] call to []
# 340| getArgument: [IntegerLiteral] 2
# 340| getReceiver: [LocalVariableAccess] __synth__0__1
# 340| getLeftOperand: [TuplePattern] (..., ...)
# 340| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
# 341| getStmt: [MethodCall] call to foo
# 341| getReceiver: [Self, SelfVariableAccess] self
# 341| getArgument: [LocalVariableAccess] x
@@ -477,7 +477,7 @@ control/loops.rb:
# 22| getAnOperand/getRightOperand: [MethodCall] call to []
# 22| getArgument: [IntegerLiteral] 1
# 22| getReceiver: [LocalVariableAccess] __synth__0__1
# 22| getLeftOperand: [TuplePattern] (..., ...)
# 22| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
# 23| getStmt: [AssignAddExpr] ... += ...
# 23| getDesugared: [AssignExpr] ... = ...
# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
@@ -518,7 +518,7 @@ control/loops.rb:
# 28| getAnOperand/getRightOperand: [MethodCall] call to []
# 28| getArgument: [IntegerLiteral] 1
# 28| getReceiver: [LocalVariableAccess] __synth__0__1
# 28| getLeftOperand: [TuplePattern] (..., ...)
# 28| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
# 29| getStmt: [AssignAddExpr] ... += ...
# 29| getDesugared: [AssignExpr] ... = ...
# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum

View File

@@ -74,8 +74,20 @@
| constants/constants.rb:20:22:20:28 | "Chuck" | Chuck |
| constants/constants.rb:20:31:20:36 | "Dave" | Dave |
| constants/constants.rb:28:11:28:15 | "foo" | foo |
| constants/constants.rb:37:30:37:33 | 1024 | 1024 |
| constants/constants.rb:39:6:39:31 | MAX_SIZE | 1024 |
| constants/constants.rb:32:16:32:17 | 42 | 42 |
| constants/constants.rb:36:18:36:19 | 43 | 43 |
| constants/constants.rb:39:30:39:33 | 1024 | 1024 |
| constants/constants.rb:41:6:41:31 | MAX_SIZE | 1024 |
| constants/constants.rb:48:18:48:19 | 41 | 41 |
| constants/constants.rb:53:17:53:29 | "fourty-four" | fourty-four |
| constants/constants.rb:55:21:55:31 | FOURTY_FOUR | 44 |
| constants/constants.rb:55:21:55:31 | FOURTY_FOUR | fourty-four |
| constants/constants.rb:56:19:56:20 | 44 | 44 |
| constants/constants.rb:57:21:57:31 | FOURTY_FOUR | 44 |
| constants/constants.rb:57:21:57:31 | FOURTY_FOUR | fourty-four |
| constants/constants.rb:63:19:63:20 | 45 | 45 |
| constants/constants.rb:65:19:65:35 | FOURTY_FIVE | 45 |
| constants/constants.rb:71:18:71:19 | 46 | 46 |
| control/cases.rb:2:5:2:5 | 0 | 0 |
| control/cases.rb:3:5:3:5 | 0 | 0 |
| control/cases.rb:4:5:4:5 | 0 | 0 |

View File

@@ -20,41 +20,87 @@ constantAccess
| constants.rb:20:13:20:37 | Array | read | Array | ConstantReadAccess |
| constants.rb:22:5:22:9 | Names | read | Names | ConstantReadAccess |
| constants.rb:23:18:23:25 | GREETING | read | GREETING | ConstantReadAccess |
| constants.rb:31:1:32:3 | ClassD | write | ClassD | ClassDeclaration |
| constants.rb:31:1:33:3 | ClassD | write | ClassD | ClassDeclaration |
| constants.rb:31:7:31:13 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:31:25:31:31 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:31:25:31:39 | ClassA | read | ClassA | ConstantReadAccess |
| constants.rb:34:1:35:3 | ModuleC | write | ModuleC | ModuleDeclaration |
| constants.rb:34:8:34:14 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:37:1:37:7 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:37:1:37:16 | ModuleB | read | ModuleB | ConstantReadAccess |
| constants.rb:37:1:37:26 | MAX_SIZE | write | MAX_SIZE | ConstantAssignment |
| constants.rb:39:6:39:12 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:39:6:39:21 | ModuleB | read | ModuleB | ConstantReadAccess |
| constants.rb:39:6:39:31 | MAX_SIZE | read | MAX_SIZE | ConstantReadAccess |
| constants.rb:41:6:41:13 | GREETING | read | GREETING | ConstantReadAccess |
| constants.rb:42:6:42:15 | GREETING | read | GREETING | ConstantReadAccess |
| constants.rb:32:3:32:12 | FOURTY_TWO | write | FOURTY_TWO | ConstantAssignment |
| constants.rb:35:1:37:3 | ModuleC | write | ModuleC | ModuleDeclaration |
| constants.rb:35:8:35:14 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:36:3:36:14 | FOURTY_THREE | write | FOURTY_THREE | ConstantAssignment |
| constants.rb:39:1:39:7 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:39:1:39:16 | ModuleB | read | ModuleB | ConstantReadAccess |
| constants.rb:39:1:39:26 | MAX_SIZE | write | MAX_SIZE | ConstantAssignment |
| constants.rb:41:6:41:12 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:41:6:41:21 | ModuleB | read | ModuleB | ConstantReadAccess |
| constants.rb:41:6:41:31 | MAX_SIZE | read | MAX_SIZE | ConstantReadAccess |
| constants.rb:43:6:43:13 | GREETING | read | GREETING | ConstantReadAccess |
| constants.rb:44:6:44:15 | GREETING | read | GREETING | ConstantReadAccess |
| constants.rb:46:1:50:3 | ModuleB | write | ModuleB | ModuleDeclaration |
| constants.rb:46:8:46:14 | ModuleA | read | ModuleA | ConstantReadAccess |
| constants.rb:47:3:49:5 | ClassB | write | ClassB | ClassDeclaration |
| constants.rb:47:18:47:21 | Base | read | Base | ConstantReadAccess |
| constants.rb:48:5:48:14 | FOURTY_ONE | write | FOURTY_ONE | ConstantAssignment |
| constants.rb:52:1:59:3 | ModuleA | write | ModuleA | ModuleDeclaration |
| constants.rb:53:3:53:13 | FOURTY_FOUR | write | FOURTY_FOUR | ConstantAssignment |
| constants.rb:54:3:58:5 | ClassB | write | ClassB | ClassDeclaration |
| constants.rb:54:9:54:15 | ModuleB | read | ModuleB | ConstantReadAccess |
| constants.rb:54:27:54:30 | Base | read | Base | ConstantReadAccess |
| constants.rb:55:21:55:31 | FOURTY_FOUR | read | FOURTY_FOUR | ConstantReadAccess |
| constants.rb:56:5:56:15 | FOURTY_FOUR | write | FOURTY_FOUR | ConstantAssignment |
| constants.rb:57:21:57:31 | FOURTY_FOUR | read | FOURTY_FOUR | ConstantReadAccess |
| constants.rb:61:1:66:3 | Mod1 | write | Mod1 | ModuleDeclaration |
| constants.rb:62:3:64:5 | Mod3 | write | Mod3 | ModuleDeclaration |
| constants.rb:63:5:63:15 | FOURTY_FIVE | write | FOURTY_FIVE | ConstantAssignment |
| constants.rb:65:19:65:22 | Mod3 | read | Mod3 | ConstantReadAccess |
| constants.rb:65:19:65:35 | FOURTY_FIVE | read | FOURTY_FIVE | ConstantReadAccess |
| constants.rb:68:1:74:3 | Mod4 | write | Mod4 | ModuleDeclaration |
| constants.rb:69:11:69:14 | Mod1 | read | Mod1 | ConstantReadAccess |
| constants.rb:70:3:72:5 | Mod5 | write | Mod5 | ModuleDeclaration |
| constants.rb:70:10:70:13 | Mod3 | read | Mod3 | ConstantReadAccess |
| constants.rb:71:5:71:14 | FOURTY_SIX | write | FOURTY_SIX | ConstantAssignment |
| constants.rb:73:18:73:21 | Mod3 | read | Mod3 | ConstantReadAccess |
| constants.rb:73:18:73:33 | FOURTY_SIX | read | FOURTY_SIX | ConstantReadAccess |
getConst
| constants.rb:1:1:15:3 | ModuleA | CONST_B | constants.rb:6:15:6:23 | "const_b" |
| constants.rb:1:1:15:3 | ModuleA | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
| constants.rb:2:5:4:7 | ModuleA::ClassA | CONST_A | constants.rb:3:19:3:27 | "const_a" |
| constants.rb:31:1:33:3 | ModuleA::ClassD | FOURTY_TWO | constants.rb:32:16:32:17 | 42 |
| constants.rb:35:1:37:3 | ModuleA::ModuleC | FOURTY_THREE | constants.rb:36:18:36:19 | 43 |
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_ONE | constants.rb:48:18:48:19 | 41 |
| constants.rb:62:3:64:5 | Mod1::Mod3 | FOURTY_FIVE | constants.rb:63:19:63:20 | 45 |
| constants.rb:70:3:72:5 | Mod1::Mod3::Mod5 | FOURTY_SIX | constants.rb:71:18:71:19 | 46 |
| file://:0:0:0:0 | Object | GREETING | constants.rb:17:12:17:64 | ... + ... |
lookupConst
| constants.rb:1:1:15:3 | ModuleA | CONST_B | constants.rb:6:15:6:23 | "const_b" |
| constants.rb:1:1:15:3 | ModuleA | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
| constants.rb:2:5:4:7 | ModuleA::ClassA | CONST_A | constants.rb:3:19:3:27 | "const_a" |
| constants.rb:2:5:4:7 | ModuleA::ClassA | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:8:5:14:7 | ModuleA::ModuleB | MAX_SIZE | constants.rb:37:30:37:33 | 1024 |
| constants.rb:9:9:10:11 | ModuleA::ModuleB::ClassB | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:8:5:14:7 | ModuleA::ModuleB | MAX_SIZE | constants.rb:39:30:39:33 | 1024 |
| constants.rb:12:9:13:11 | ModuleA::ModuleB::ClassC | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:31:1:32:3 | ModuleA::ClassD | CONST_A | constants.rb:3:19:3:27 | "const_a" |
| constants.rb:31:1:32:3 | ModuleA::ClassD | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:31:1:33:3 | ModuleA::ClassD | CONST_A | constants.rb:3:19:3:27 | "const_a" |
| constants.rb:31:1:33:3 | ModuleA::ClassD | FOURTY_TWO | constants.rb:32:16:32:17 | 42 |
| constants.rb:31:1:33:3 | ModuleA::ClassD | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:35:1:37:3 | ModuleA::ModuleC | FOURTY_THREE | constants.rb:36:18:36:19 | 43 |
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_ONE | constants.rb:48:18:48:19 | 41 |
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:62:3:64:5 | Mod1::Mod3 | FOURTY_FIVE | constants.rb:63:19:63:20 | 45 |
| constants.rb:70:3:72:5 | Mod1::Mod3::Mod5 | FOURTY_SIX | constants.rb:71:18:71:19 | 46 |
| file://:0:0:0:0 | Object | GREETING | constants.rb:17:12:17:64 | ... + ... |
constantValue
| constants.rb:17:22:17:45 | CONST_A | constants.rb:3:19:3:27 | "const_a" |
| constants.rb:17:49:17:64 | CONST_B | constants.rb:6:15:6:23 | "const_b" |
| constants.rb:23:18:23:25 | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:39:6:39:31 | MAX_SIZE | constants.rb:37:30:37:33 | 1024 |
| constants.rb:41:6:41:13 | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:42:6:42:15 | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:41:6:41:31 | MAX_SIZE | constants.rb:39:30:39:33 | 1024 |
| constants.rb:43:6:43:13 | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:44:6:44:15 | GREETING | constants.rb:17:12:17:64 | ... + ... |
| constants.rb:55:21:55:31 | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
| constants.rb:55:21:55:31 | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
| constants.rb:57:21:57:31 | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
| constants.rb:57:21:57:31 | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
| constants.rb:65:19:65:35 | FOURTY_FIVE | constants.rb:63:19:63:20 | 45 |
constantWriteAccessQualifiedName
| constants.rb:1:1:15:3 | ModuleA | ModuleA |
| constants.rb:2:5:4:7 | ClassA | ModuleA::ClassA |
@@ -65,6 +111,25 @@ constantWriteAccessQualifiedName
| constants.rb:12:9:13:11 | ClassC | ModuleA::ModuleB::ClassC |
| constants.rb:17:1:17:8 | GREETING | GREETING |
| constants.rb:20:5:20:9 | Names | Names |
| constants.rb:31:1:32:3 | ClassD | ClassD |
| constants.rb:34:1:35:3 | ModuleC | ModuleC |
| constants.rb:37:1:37:26 | MAX_SIZE | MAX_SIZE |
| constants.rb:31:1:33:3 | ClassD | ModuleA::ClassD |
| constants.rb:32:3:32:12 | FOURTY_TWO | ModuleA::ClassD::FOURTY_TWO |
| constants.rb:35:1:37:3 | ModuleC | ModuleA::ModuleC |
| constants.rb:36:3:36:14 | FOURTY_THREE | ModuleA::ModuleC::FOURTY_THREE |
| constants.rb:39:1:39:26 | MAX_SIZE | ModuleA::ModuleB::MAX_SIZE |
| constants.rb:46:1:50:3 | ModuleB | ModuleA::ModuleB |
| constants.rb:47:3:49:5 | ClassB | ModuleA::ModuleB::ClassB |
| constants.rb:48:5:48:14 | FOURTY_ONE | ModuleA::ModuleB::ClassB::FOURTY_ONE |
| constants.rb:52:1:59:3 | ModuleA | ModuleA |
| constants.rb:53:3:53:13 | FOURTY_FOUR | ModuleA::FOURTY_FOUR |
| constants.rb:54:3:58:5 | ClassB | ModuleA::ModuleB::ClassB |
| constants.rb:54:3:58:5 | ClassB | ModuleB::ClassB |
| constants.rb:56:5:56:15 | FOURTY_FOUR | ModuleA::ModuleB::ClassB::FOURTY_FOUR |
| constants.rb:56:5:56:15 | FOURTY_FOUR | ModuleB::ClassB::FOURTY_FOUR |
| constants.rb:61:1:66:3 | Mod1 | Mod1 |
| constants.rb:62:3:64:5 | Mod3 | Mod1::Mod3 |
| constants.rb:63:5:63:15 | FOURTY_FIVE | Mod1::Mod3::FOURTY_FIVE |
| constants.rb:68:1:74:3 | Mod4 | Mod4 |
| constants.rb:70:3:72:5 | Mod5 | Mod1::Mod3::Mod5 |
| constants.rb:70:3:72:5 | Mod5 | Mod3::Mod5 |
| constants.rb:71:5:71:14 | FOURTY_SIX | Mod1::Mod3::Mod5::FOURTY_SIX |
| constants.rb:71:5:71:14 | FOURTY_SIX | Mod3::Mod5::FOURTY_SIX |

View File

@@ -18,5 +18,5 @@ query Expr lookupConst(Module m, string name) { result = M::lookupConst(m, name)
query predicate constantValue(ConstantReadAccess a, Expr e) { e = a.getValue() }
query predicate constantWriteAccessQualifiedName(ConstantWriteAccess w, string qualifiedName) {
w.getQualifiedName() = qualifiedName
w.getAQualifiedName() = qualifiedName
}

View File

@@ -29,9 +29,11 @@ def foo
end
class ModuleA::ClassD < ModuleA::ClassA
FOURTY_TWO = 42
end
module ModuleA::ModuleC
FOURTY_THREE = 43
end
ModuleA::ModuleB::MAX_SIZE = 1024
@@ -40,3 +42,33 @@ puts ModuleA::ModuleB::MAX_SIZE
puts GREETING
puts ::GREETING
module ModuleA::ModuleB
class ClassB < Base
FOURTY_ONE = 41
end
end
module ModuleA
FOURTY_FOUR = "fourty-four"
class ModuleB::ClassB < Base
@@fourty_four = FOURTY_FOUR # refers to ::ModuleA::FOURTY_FOUR
FOURTY_FOUR = 44
@@fourty_four = FOURTY_FOUR # refers to ::ModuleA::ModuleB::ClassB::FOURTY_FOUR
end
end
module Mod1
module Mod3
FOURTY_FIVE = 45
end
@@fourty_five = Mod3::FOURTY_FIVE
end
module Mod4
include Mod1
module Mod3::Mod5
FOURTY_SIX = 46
end
@@fourty_six = Mod3::FOURTY_SIX
end

View File

@@ -10,10 +10,10 @@ query predicate caseElseBranches(CaseExpr c, StmtSequence elseBranch) {
query predicate caseNoElseBranches(CaseExpr c) { not exists(c.getElseBranch()) }
query predicate caseWhenBranches(CaseExpr c, WhenExpr when, int pIndex, Expr p, StmtSequence body) {
query predicate caseWhenBranches(CaseExpr c, WhenClause when, int pIndex, Expr p, StmtSequence body) {
when = c.getABranch() and
p = when.getPattern(pIndex) and
body = when.getBody()
}
query predicate caseAllBranches(CaseExpr c, int n, Expr branch) { branch = c.getBranch(n) }
query predicate caseAllBranches(CaseExpr c, int n, AstNode branch) { branch = c.getBranch(n) }

View File

@@ -13,13 +13,13 @@ query predicate conditionalLoops(
cond = l.getCondition()
}
query predicate forExprs(ForExpr f, Pattern p, StmtSequence body, int i, Stmt bodyChild) {
query predicate forExprs(ForExpr f, LhsExpr p, StmtSequence body, int i, Stmt bodyChild) {
p = f.getPattern() and
body = f.getBody() and
bodyChild = body.getStmt(i)
}
query predicate forExprsTuplePatterns(ForExpr f, TuplePattern tp, int i, Pattern cp) {
query predicate forExprsTuplePatterns(ForExpr f, DestructuredLhsExpr tp, int i, Expr cp) {
tp = f.getPattern() and
cp = tp.getElement(i)
}

View File

@@ -73,7 +73,7 @@ paramsInMethods
| params.rb:4:1:5:3 | identifier_method_params | 0 | params.rb:4:30:4:32 | foo | SimpleParameter |
| params.rb:4:1:5:3 | identifier_method_params | 1 | params.rb:4:35:4:37 | bar | SimpleParameter |
| params.rb:4:1:5:3 | identifier_method_params | 2 | params.rb:4:40:4:42 | baz | SimpleParameter |
| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | TuplePatternParameter |
| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | DestructuredParameter |
| params.rb:30:1:31:3 | method_with_splat | 0 | params.rb:30:23:30:28 | wibble | SimpleParameter |
| params.rb:30:1:31:3 | method_with_splat | 1 | params.rb:30:31:30:36 | *splat | SplatParameter |
| params.rb:30:1:31:3 | method_with_splat | 2 | params.rb:30:39:30:52 | **double_splat | HashSplatParameter |
@@ -90,7 +90,7 @@ paramsInMethods
paramsInBlocks
| params.rb:9:11:11:3 | do ... end | 0 | params.rb:9:15:9:17 | key | SimpleParameter |
| params.rb:9:11:11:3 | do ... end | 1 | params.rb:9:20:9:24 | value | SimpleParameter |
| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | TuplePatternParameter |
| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | DestructuredParameter |
| params.rb:34:12:35:3 | do ... end | 0 | params.rb:34:16:34:18 | val | SimpleParameter |
| params.rb:34:12:35:3 | do ... end | 1 | params.rb:34:21:34:26 | *splat | SplatParameter |
| params.rb:34:12:35:3 | do ... end | 2 | params.rb:34:29:34:42 | **double_splat | HashSplatParameter |
@@ -103,8 +103,8 @@ paramsInBlocks
paramsInLambdas
| params.rb:14:7:14:33 | -> { ... } | 0 | params.rb:14:11:14:13 | foo | SimpleParameter |
| params.rb:14:7:14:33 | -> { ... } | 1 | params.rb:14:16:14:18 | bar | SimpleParameter |
| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | TuplePatternParameter |
| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | TuplePatternParameter |
| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | DestructuredParameter |
| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | DestructuredParameter |
| params.rb:38:22:38:47 | -> { ... } | 0 | params.rb:38:26:38:26 | x | SimpleParameter |
| params.rb:38:22:38:47 | -> { ... } | 1 | params.rb:38:29:38:33 | *blah | SplatParameter |
| params.rb:38:22:38:47 | -> { ... } | 2 | params.rb:38:36:38:43 | **wibble | HashSplatParameter |
@@ -122,10 +122,10 @@ params
| params.rb:9:20:9:24 | value | 1 | SimpleParameter |
| params.rb:14:11:14:13 | foo | 0 | SimpleParameter |
| params.rb:14:16:14:18 | bar | 1 | SimpleParameter |
| params.rb:17:31:17:39 | (..., ...) | 0 | TuplePatternParameter |
| params.rb:22:15:22:20 | (..., ...) | 0 | TuplePatternParameter |
| params.rb:25:23:25:37 | (..., ...) | 0 | TuplePatternParameter |
| params.rb:25:40:25:54 | (..., ...) | 1 | TuplePatternParameter |
| params.rb:17:31:17:39 | (..., ...) | 0 | DestructuredParameter |
| params.rb:22:15:22:20 | (..., ...) | 0 | DestructuredParameter |
| params.rb:25:23:25:37 | (..., ...) | 0 | DestructuredParameter |
| params.rb:25:40:25:54 | (..., ...) | 1 | DestructuredParameter |
| params.rb:30:23:30:28 | wibble | 0 | SimpleParameter |
| params.rb:30:31:30:36 | *splat | 1 | SplatParameter |
| params.rb:30:39:30:52 | **double_splat | 2 | HashSplatParameter |

View File

@@ -6,7 +6,7 @@ query predicate idParams(NamedParameter np, string name) { name = np.getName() }
query predicate blockParams(BlockParameter bp, string name) { name = bp.getName() }
query predicate patternParams(TuplePatternParameter tpp, Pattern child, int childIndex) {
query predicate patternParams(DestructuredParameter tpp, AstNode child, int childIndex) {
tpp.getElement(childIndex) = child
}

View File

@@ -486,7 +486,7 @@ break_ensure.rb:
case.rb:
# 1| enter if_in_case
#-----| -> case ...
#-----| -> self
# 1| enter case.rb
#-----| -> if_in_case
@@ -505,7 +505,7 @@ case.rb:
#-----| -> exit case.rb
# 2| case ...
#-----| -> self
#-----| -> exit if_in_case (normal)
# 2| call to x1
#-----| -> when ...
@@ -521,7 +521,7 @@ case.rb:
#-----| match -> self
# 3| then ...
#-----| -> exit if_in_case (normal)
#-----| -> case ...
# 3| ( ... )
#-----| -> then ...
@@ -552,11 +552,11 @@ case.rb:
#-----| -> 2
# 4| 2
#-----| no-match -> case ...
#-----| match -> self
#-----| no-match -> exit if_in_case (normal)
# 4| then ...
#-----| -> exit if_in_case (normal)
#-----| -> case ...
# 4| call to puts
#-----| -> then ...
@@ -579,10 +579,10 @@ case.rb:
#-----| -> exit case_match
# 8| value
#-----| -> case ...
#-----| -> value
# 9| case ...
#-----| -> value
#-----| -> exit case_match (normal)
# 9| value
#-----| -> in ... then ...
@@ -591,8 +591,8 @@ case.rb:
#-----| -> 0
# 10| 0
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match (normal)
# 11| in ... then ...
#-----| -> 1
@@ -602,7 +602,7 @@ case.rb:
#-----| match -> 3
# 11| then ...
#-----| -> exit case_match (normal)
#-----| -> case ...
# 11| 3
#-----| -> then ...
@@ -615,7 +615,7 @@ case.rb:
#-----| match -> 4
# 12| then ...
#-----| -> exit case_match (normal)
#-----| -> case ...
# 13| 4
#-----| -> then ...
@@ -637,7 +637,7 @@ case.rb:
#-----| -> ... == ...
# 14| then ...
#-----| -> exit case_match (normal)
#-----| -> case ...
# 14| 6
#-----| -> then ...
@@ -659,13 +659,13 @@ case.rb:
#-----| -> ... < ...
# 15| then ...
#-----| -> exit case_match (normal)
#-----| -> case ...
# 15| 7
#-----| -> then ...
# 16| else ...
#-----| -> exit case_match (normal)
#-----| -> case ...
# 16| 8
#-----| -> else ...
@@ -685,10 +685,10 @@ case.rb:
#-----| -> exit case_match_no_match
# 20| value
#-----| -> case ...
#-----| -> value
# 21| case ...
#-----| -> value
#-----| -> exit case_match_no_match (normal)
# 21| value
#-----| -> in ... then ...
@@ -697,8 +697,8 @@ case.rb:
#-----| -> 1
# 22| 1
#-----| match -> case ...
#-----| raise -> exit case_match_no_match (abnormal)
#-----| match -> exit case_match_no_match (normal)
# 26| enter case_match_raise
#-----| -> value
@@ -715,10 +715,10 @@ case.rb:
#-----| -> exit case_match_raise
# 26| value
#-----| -> case ...
#-----| -> value
# 27| case ...
#-----| -> value
#-----| -> exit case_match_raise (normal)
# 27| value
#-----| -> in ... then ...
@@ -730,8 +730,8 @@ case.rb:
#-----| -> x
# 28| -> { ... }
#-----| match -> case ...
#-----| raise -> exit case_match_raise (abnormal)
#-----| match -> exit case_match_raise (normal)
# 28| exit -> { ... }
@@ -765,10 +765,10 @@ case.rb:
#-----| -> exit case_match_array
# 32| value
#-----| -> case ...
#-----| -> value
# 33| case ...
#-----| -> value
#-----| -> exit case_match_array (normal)
# 33| value
#-----| -> in ... then ...
@@ -777,8 +777,8 @@ case.rb:
#-----| -> [ ..., * ]
# 34| [ ..., * ]
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_array (normal)
# 35| in ... then ...
#-----| -> [ ..., * ]
@@ -788,7 +788,7 @@ case.rb:
#-----| match -> x
# 35| x
#-----| match -> exit case_match_array (normal)
#-----| match -> case ...
# 36| in ... then ...
#-----| -> [ ..., * ]
@@ -798,7 +798,7 @@ case.rb:
#-----| match -> x
# 36| x
#-----| match -> exit case_match_array (normal)
#-----| match -> case ...
# 37| in ... then ...
#-----| -> Bar
@@ -824,7 +824,7 @@ case.rb:
#-----| match -> e
# 37| e
#-----| match -> exit case_match_array (normal)
#-----| match -> case ...
# 41| enter case_match_find
#-----| -> value
@@ -841,10 +841,10 @@ case.rb:
#-----| -> exit case_match_find
# 41| value
#-----| -> case ...
#-----| -> value
# 42| case ...
#-----| -> value
#-----| -> exit case_match_find (normal)
# 42| value
#-----| -> in ... then ...
@@ -868,7 +868,7 @@ case.rb:
#-----| raise -> exit case_match_find (abnormal)
# 43| y
#-----| -> exit case_match_find (normal)
#-----| -> case ...
# 47| enter case_match_hash
#-----| -> value
@@ -885,10 +885,10 @@ case.rb:
#-----| -> exit case_match_hash
# 47| value
#-----| -> case ...
#-----| -> value
# 48| case ...
#-----| -> value
#-----| -> exit case_match_hash (normal)
# 48| value
#-----| -> in ... then ...
@@ -912,7 +912,7 @@ case.rb:
#-----| match -> rest
# 49| rest
#-----| -> exit case_match_hash (normal)
#-----| -> case ...
# 50| in ... then ...
#-----| -> Bar
@@ -926,15 +926,15 @@ case.rb:
#-----| no-match -> in ... then ...
# 50| 1
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_hash (normal)
# 51| in ... then ...
#-----| -> Bar
# 51| { ..., ** }
#-----| match -> case ...
#-----| raise -> exit case_match_hash (abnormal)
#-----| match -> exit case_match_hash (normal)
# 51| Bar
#-----| match -> { ..., ** }
@@ -952,10 +952,10 @@ case.rb:
#-----| -> exit case_match_variable
# 55| value
#-----| -> case ...
#-----| -> value
# 56| case ...
#-----| -> value
#-----| -> exit case_match_variable (normal)
# 56| value
#-----| -> in ... then ...
@@ -964,14 +964,14 @@ case.rb:
#-----| -> 5
# 57| 5
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_variable (normal)
# 58| in ... then ...
#-----| -> var
# 58| var
#-----| match -> exit case_match_variable (normal)
#-----| match -> case ...
# 63| enter case_match_underscore
#-----| -> value
@@ -985,10 +985,10 @@ case.rb:
#-----| -> exit case_match_underscore
# 63| value
#-----| -> case ...
#-----| -> value
# 64| case ...
#-----| -> value
#-----| -> exit case_match_underscore (normal)
# 64| value
#-----| -> in ... then ...
@@ -1000,11 +1000,11 @@ case.rb:
#-----| -> 5
# 65| 5
#-----| match -> case ...
#-----| no-match -> _
#-----| match -> exit case_match_underscore (normal)
# 65| _
#-----| match -> exit case_match_underscore (normal)
#-----| match -> case ...
# 69| enter case_match_various
#-----| -> value
@@ -1024,7 +1024,7 @@ case.rb:
#-----| -> foo
# 70| ... = ...
#-----| -> case ...
#-----| -> value
# 70| foo
#-----| -> 42
@@ -1033,7 +1033,7 @@ case.rb:
#-----| -> ... = ...
# 72| case ...
#-----| -> value
#-----| -> exit case_match_various (normal)
# 72| value
#-----| -> in ... then ...
@@ -1042,8 +1042,8 @@ case.rb:
#-----| -> 5
# 73| 5
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 74| in ... then ...
#-----| -> ^...
@@ -1052,22 +1052,22 @@ case.rb:
#-----| -> foo
# 74| foo
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 75| in ... then ...
#-----| -> "string"
# 75| "string"
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 76| in ... then ...
#-----| -> Array
# 76| call to []
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 76| Array
#-----| -> "foo"
@@ -1082,8 +1082,8 @@ case.rb:
#-----| -> Array
# 77| call to []
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 77| Array
#-----| -> :"foo"
@@ -1098,8 +1098,8 @@ case.rb:
#-----| -> /.*abc[0-9]/
# 78| /.*abc[0-9]/
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 79| in ... then ...
#-----| -> 5
@@ -1108,8 +1108,8 @@ case.rb:
#-----| -> 10
# 79| _ .. _
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 79| 10
#-----| -> _ .. _
@@ -1118,8 +1118,8 @@ case.rb:
#-----| -> 10
# 80| _ .. _
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 80| 10
#-----| -> _ .. _
@@ -1131,8 +1131,8 @@ case.rb:
#-----| -> _ .. _
# 81| _ .. _
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 82| in ... then ...
#-----| -> ... => ...
@@ -1145,7 +1145,7 @@ case.rb:
#-----| match -> x
# 82| x
#-----| -> exit case_match_various (normal)
#-----| -> case ...
# 83| in ... then ...
#-----| -> ... | ...
@@ -1154,26 +1154,26 @@ case.rb:
#-----| -> 5
# 83| 5
#-----| match -> case ...
#-----| no-match -> ^...
#-----| match -> exit case_match_various (normal)
# 83| ^...
#-----| -> foo
# 83| foo
#-----| match -> case ...
#-----| no-match -> "string"
#-----| match -> exit case_match_various (normal)
# 83| "string"
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 84| in ... then ...
#-----| -> Foo
# 84| Bar
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 84| Foo
#-----| -> Bar
@@ -1185,8 +1185,8 @@ case.rb:
#-----| -> x
# 85| -> { ... }
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 85| exit -> { ... }
@@ -1209,15 +1209,15 @@ case.rb:
#-----| -> :foo
# 86| :foo
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 87| in ... then ...
#-----| -> :"foo bar"
# 87| :"foo bar"
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 88| in ... then ...
#-----| -> ... | ...
@@ -1226,15 +1226,15 @@ case.rb:
#-----| -> 5
# 88| - ...
#-----| match -> case ...
#-----| no-match -> 10
#-----| match -> exit case_match_various (normal)
# 88| 5
#-----| -> - ...
# 88| + ...
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 88| 10
#-----| -> + ...
@@ -1246,32 +1246,32 @@ case.rb:
#-----| -> nil
# 89| nil
#-----| match -> case ...
#-----| no-match -> self
#-----| match -> exit case_match_various (normal)
# 89| self
#-----| match -> case ...
#-----| no-match -> true
#-----| match -> exit case_match_various (normal)
# 89| true
#-----| match -> case ...
#-----| no-match -> false
#-----| match -> exit case_match_various (normal)
# 89| false
#-----| match -> case ...
#-----| no-match -> __LINE__
#-----| match -> exit case_match_various (normal)
# 89| __LINE__
#-----| match -> case ...
#-----| no-match -> __FILE__
#-----| match -> exit case_match_various (normal)
# 89| __FILE__
#-----| match -> case ...
#-----| no-match -> __ENCODING__
#-----| match -> exit case_match_various (normal)
# 89| __ENCODING__
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 90| in ... then ...
#-----| -> ( ... )
@@ -1283,8 +1283,8 @@ case.rb:
#-----| -> _ .. _
# 90| _ .. _
#-----| match -> case ...
#-----| no-match -> in ... then ...
#-----| match -> exit case_match_various (normal)
# 91| in ... then ...
#-----| -> ( ... )
@@ -1296,20 +1296,20 @@ case.rb:
#-----| -> 0
# 91| 0
#-----| match -> case ...
#-----| no-match -> ""
#-----| match -> exit case_match_various (normal)
# 91| ""
#-----| no-match -> [ ..., * ]
#-----| match -> exit case_match_various (normal)
#-----| match -> case ...
# 91| [ ..., * ]
#-----| match -> case ...
#-----| no-match -> { ..., ** }
#-----| match -> exit case_match_various (normal)
# 91| { ..., ** }
#-----| match -> case ...
#-----| raise -> exit case_match_various (abnormal)
#-----| match -> exit case_match_various (normal)
# 95| enter case_match_guard_no_else
#-----| -> value
@@ -1326,10 +1326,10 @@ case.rb:
#-----| -> exit case_match_guard_no_else
# 95| value
#-----| -> case ...
#-----| -> value
# 96| case ...
#-----| -> value
#-----| -> exit case_match_guard_no_else (normal)
# 96| value
#-----| -> in ... then ...
@@ -1351,7 +1351,7 @@ case.rb:
#-----| -> ... == ...
# 97| then ...
#-----| -> exit case_match_guard_no_else (normal)
#-----| -> case ...
# 97| 6
#-----| -> then ...
@@ -1703,7 +1703,7 @@ cfg.rb:
#-----| false -> if ...
# 39| call to puts
#-----| -> case ...
#-----| -> 10
# 39| self
#-----| -> 42
@@ -1712,7 +1712,7 @@ cfg.rb:
#-----| -> call to puts
# 41| case ...
#-----| -> 10
#-----| -> when ...
# 41| 10
#-----| -> when ...
@@ -1776,7 +1776,7 @@ cfg.rb:
#-----| -> call to puts
# 47| case ...
#-----| -> when ...
#-----| -> chained
# 48| when ...
#-----| -> b
@@ -1792,7 +1792,7 @@ cfg.rb:
#-----| -> ... == ...
# 48| then ...
#-----| -> chained
#-----| -> case ...
# 48| call to puts
#-----| -> then ...
@@ -1817,7 +1817,7 @@ cfg.rb:
#-----| -> ... == ...
# 49| ... > ...
#-----| false -> chained
#-----| false -> case ...
#-----| true -> self
# 49| b
@@ -1827,7 +1827,7 @@ cfg.rb:
#-----| -> ... > ...
# 49| then ...
#-----| -> chained
#-----| -> case ...
# 49| call to puts
#-----| -> then ...
@@ -1847,6 +1847,9 @@ cfg.rb:
# 52| "a"
#-----| -> chained
# 52| "..." "..."
#-----| -> ... = ...
# 52| "#{...}"
#-----| -> "string"
@@ -1857,7 +1860,7 @@ cfg.rb:
#-----| -> #{...}
# 52| "string"
#-----| -> ... = ...
#-----| -> "..." "..."
# 54| ... = ...
#-----| -> Silly
@@ -1941,12 +1944,12 @@ cfg.rb:
# 62| call to []
#-----| -> * ...
# 62| ...
#-----| -> ...
# 62| 1
#-----| -> call to []
# 62| ...
#-----| -> ...
# 62| __synth__0
#-----| -> 1
@@ -2416,13 +2419,13 @@ cfg.rb:
#-----| -> b
# 108| self
#-----| -> <<SQL
#-----| -> table
# 108| ( ... )
#-----| -> call to puts
# 108| <<SQL
#-----| -> table
#-----| -> ( ... )
# 109| #{...}
#-----| -> type
@@ -2431,7 +2434,7 @@ cfg.rb:
#-----| -> #{...}
# 110| #{...}
#-----| -> ( ... )
#-----| -> <<SQL
# 110| type
#-----| -> #{...}
@@ -2641,23 +2644,23 @@ cfg.rb:
#-----| -> EmptyModule
# 134| EmptyModule
#-----| -> ... rescue ...
#-----| -> 1
# 136| ... / ...
#-----| -> ... rescue ...
#-----| raise -> self
#-----| -> __synth__0
# 136| 1
#-----| -> 0
# 136| ... rescue ...
#-----| -> 1
#-----| -> __synth__0
# 136| 0
#-----| -> ... / ...
# 136| call to puts
#-----| -> __synth__0
#-----| -> ... rescue ...
# 136| self
#-----| -> "div by zero"
@@ -2704,6 +2707,9 @@ cfg.rb:
# 138| __synth__0
#-----| -> -1
# 138| ..., ...
#-----| -> * ...
# 138| 1
#-----| -> 2
@@ -2720,7 +2726,7 @@ cfg.rb:
#-----| -> 3
# 138| 3
#-----| -> * ...
#-----| -> ..., ...
# 140| M
#-----| -> Constant
@@ -3270,6 +3276,9 @@ cfg.rb:
#-----| -> b
# 197| b
#-----| -> ...
# 197| ...
#-----| -> call to bar
desugar.rb:
@@ -3626,12 +3635,12 @@ desugar.rb:
# 22| call to []
#-----| -> ... = ...
# 22| ...
#-----| -> ...
# 22| -1
#-----| -> call to []
# 22| ...
#-----| -> ...
# 22| __synth__0
#-----| -> -1
@@ -3706,12 +3715,12 @@ desugar.rb:
# 26| call to []
#-----| -> * ...
# 26| ...
#-----| -> ...
# 26| 1
#-----| -> call to []
# 26| ...
#-----| -> ...
# 26| __synth__0
#-----| -> 1
@@ -4905,7 +4914,7 @@ raise.rb:
#-----| true -> self
# 17| call to raise
#-----| raise -> rescue ...
#-----| raise -> ExceptionA
# 17| self
#-----| -> ExceptionA
@@ -4914,14 +4923,14 @@ raise.rb:
#-----| -> call to raise
# 19| rescue ...
#-----| -> ExceptionA
#-----| -> self
# 19| ExceptionA
#-----| match -> self
#-----| raise -> exit m2 (abnormal)
# 19| then ...
#-----| -> self
#-----| -> rescue ...
# 20| call to puts
#-----| -> then ...
@@ -4963,7 +4972,7 @@ raise.rb:
#-----| true -> self
# 28| call to raise
#-----| raise -> rescue ...
#-----| raise -> self
# 28| self
#-----| -> ExceptionA
@@ -4975,7 +4984,7 @@ raise.rb:
#-----| -> self
# 30| then ...
#-----| -> self
#-----| -> rescue ...
# 31| call to puts
#-----| -> then ...
@@ -5017,7 +5026,7 @@ raise.rb:
#-----| true -> self
# 39| call to raise
#-----| raise -> rescue ...
#-----| raise -> e
# 39| self
#-----| -> ExceptionA
@@ -5026,13 +5035,13 @@ raise.rb:
#-----| -> call to raise
# 41| rescue ...
#-----| -> e
#-----| -> self
# 41| e
#-----| -> self
# 41| then ...
#-----| -> self
#-----| -> rescue ...
# 42| call to puts
#-----| -> then ...
@@ -5074,7 +5083,7 @@ raise.rb:
#-----| true -> self
# 50| call to raise
#-----| raise -> rescue ...
#-----| raise -> e
# 50| self
#-----| -> ExceptionA
@@ -5083,10 +5092,10 @@ raise.rb:
#-----| -> call to raise
# 52| rescue ...
#-----| -> e
#-----| -> self
# 52| e
#-----| -> self
#-----| -> rescue ...
# 54| call to puts
#-----| -> exit m5 (normal)
@@ -5122,7 +5131,7 @@ raise.rb:
#-----| true -> self
# 60| call to raise
#-----| raise -> rescue ...
#-----| raise -> ExceptionA
# 60| self
#-----| -> ExceptionA
@@ -5131,7 +5140,7 @@ raise.rb:
#-----| -> call to raise
# 62| rescue ...
#-----| -> ExceptionA
#-----| -> self
# 62| ExceptionA
#-----| no-match -> ExceptionB
@@ -5145,7 +5154,7 @@ raise.rb:
#-----| -> self
# 62| then ...
#-----| -> self
#-----| -> rescue ...
# 63| call to puts
#-----| -> then ...
@@ -5804,7 +5813,7 @@ raise.rb:
#-----| true -> self
# 131| call to raise
#-----| raise -> rescue ...
#-----| raise -> ExceptionA
# 131| self
#-----| -> ExceptionA
@@ -5813,21 +5822,21 @@ raise.rb:
#-----| -> call to raise
# 133| rescue ...
#-----| -> ExceptionA
#-----| -> self
# 133| ExceptionA
#-----| no-match -> rescue ...
#-----| match -> self
#-----| match -> rescue ...
#-----| no-match -> ExceptionB
# 134| rescue ...
#-----| -> ExceptionB
#-----| -> self
# 134| ExceptionB
#-----| match -> self
#-----| raise -> [ensure: raise] self
# 134| then ...
#-----| -> self
#-----| -> rescue ...
# 135| call to puts
#-----| -> then ...

View File

@@ -191,6 +191,7 @@ positionalArguments
| cfg.rb:191:3:191:10 | yield ... | cfg.rb:191:9:191:10 | 42 |
| cfg.rb:194:16:194:21 | call to puts | cfg.rb:194:21:194:21 | x |
| cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:7:197:7 | b |
| cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:10:197:12 | ... |
| desugar.rb:2:5:2:6 | ... + ... | desugar.rb:2:8:2:8 | 1 |
| desugar.rb:6:3:6:13 | call to count= | desugar.rb:6:3:6:13 | ... = ... |
| desugar.rb:10:3:10:10 | call to []= | desugar.rb:10:3:10:10 | ... = ... |

View File

@@ -70,3 +70,33 @@
| local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x |
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x |
| local_dataflow.rb:51:9:51:15 | "break" | local_dataflow.rb:51:3:51:15 | break |
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:60:15:60:15 | x |
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:61:12:61:12 | x |
| local_dataflow.rb:61:7:68:5 | case ... | local_dataflow.rb:61:3:68:5 | ... = ... |
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:63:15:63:15 | x |
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:65:6:65:6 | x |
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:67:5:67:5 | x |
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:69:12:69:12 | x |
| local_dataflow.rb:62:10:62:15 | then ... | local_dataflow.rb:61:7:68:5 | case ... |
| local_dataflow.rb:62:15:62:15 | 3 | local_dataflow.rb:62:10:62:15 | then ... |
| local_dataflow.rb:63:10:63:15 | then ... | local_dataflow.rb:61:7:68:5 | case ... |
| local_dataflow.rb:63:15:63:15 | x | local_dataflow.rb:63:10:63:15 | then ... |
| local_dataflow.rb:63:15:63:15 | x | local_dataflow.rb:69:12:69:12 | x |
| local_dataflow.rb:64:9:65:6 | then ... | local_dataflow.rb:61:7:68:5 | case ... |
| local_dataflow.rb:65:6:65:6 | x | local_dataflow.rb:64:9:65:6 | then ... |
| local_dataflow.rb:65:6:65:6 | x | local_dataflow.rb:69:12:69:12 | x |
| local_dataflow.rb:66:3:67:5 | else ... | local_dataflow.rb:61:7:68:5 | case ... |
| local_dataflow.rb:67:5:67:5 | x | local_dataflow.rb:66:3:67:5 | else ... |
| local_dataflow.rb:67:5:67:5 | x | local_dataflow.rb:69:12:69:12 | x |
| local_dataflow.rb:69:7:76:5 | case ... | local_dataflow.rb:69:3:76:5 | ... = ... |
| local_dataflow.rb:69:12:69:12 | x | local_dataflow.rb:71:13:71:13 | x |
| local_dataflow.rb:69:12:69:12 | x | local_dataflow.rb:73:7:73:7 | x |
| local_dataflow.rb:69:12:69:12 | x | local_dataflow.rb:75:6:75:6 | x |
| local_dataflow.rb:70:8:70:13 | then ... | local_dataflow.rb:69:7:76:5 | case ... |
| local_dataflow.rb:70:13:70:13 | 4 | local_dataflow.rb:70:8:70:13 | then ... |
| local_dataflow.rb:71:8:71:13 | then ... | local_dataflow.rb:69:7:76:5 | case ... |
| local_dataflow.rb:71:13:71:13 | x | local_dataflow.rb:71:8:71:13 | then ... |
| local_dataflow.rb:72:7:73:7 | then ... | local_dataflow.rb:69:7:76:5 | case ... |
| local_dataflow.rb:73:7:73:7 | x | local_dataflow.rb:72:7:73:7 | then ... |
| local_dataflow.rb:74:3:75:6 | else ... | local_dataflow.rb:69:7:76:5 | case ... |
| local_dataflow.rb:75:6:75:6 | x | local_dataflow.rb:74:3:75:6 | else ... |

View File

@@ -12,39 +12,40 @@ ret
| local_dataflow.rb:50:3:50:13 | next |
| local_dataflow.rb:51:3:51:15 | break |
| local_dataflow.rb:52:3:52:10 | "normal" |
| local_dataflow.rb:69:3:76:5 | ... = ... |
arg
| local_dataflow.rb:3:8:3:10 | self | local_dataflow.rb:3:8:3:10 | call to p | -1 |
| local_dataflow.rb:3:10:3:10 | a | local_dataflow.rb:3:8:3:10 | call to p | 0 |
| local_dataflow.rb:6:8:6:8 | a | local_dataflow.rb:6:10:6:11 | ... + ... | -1 |
| local_dataflow.rb:6:13:6:13 | b | local_dataflow.rb:6:10:6:11 | ... + ... | 0 |
| local_dataflow.rb:9:9:9:15 | Array | local_dataflow.rb:9:9:9:15 | call to [] | -1 |
| local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | 0 |
| local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | 1 |
| local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | 2 |
| local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | -2 |
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | -1 |
| local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | -1 |
| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:12:3:12:5 | call to p | -1 |
| local_dataflow.rb:12:5:12:5 | x | local_dataflow.rb:12:3:12:5 | call to p | 0 |
| local_dataflow.rb:15:1:17:3 | { ... } | local_dataflow.rb:15:1:17:3 | call to each | -2 |
| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | call to each | -1 |
| local_dataflow.rb:19:1:21:3 | { ... } | local_dataflow.rb:19:1:21:3 | call to each | -2 |
| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | call to each | -1 |
| local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... | -1 |
| local_dataflow.rb:20:10:20:10 | 1 | local_dataflow.rb:20:6:20:10 | ... > ... | 0 |
| local_dataflow.rb:35:6:35:6 | x | local_dataflow.rb:35:6:35:11 | ... == ... | -1 |
| local_dataflow.rb:35:11:35:11 | 4 | local_dataflow.rb:35:6:35:11 | ... == ... | 0 |
| local_dataflow.rb:42:6:42:6 | x | local_dataflow.rb:42:6:42:11 | ... == ... | -1 |
| local_dataflow.rb:42:11:42:11 | 4 | local_dataflow.rb:42:6:42:11 | ... == ... | 0 |
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:49:1:53:3 | call to m | -1 |
| local_dataflow.rb:49:3:53:3 | do ... end | local_dataflow.rb:49:1:53:3 | call to m | -2 |
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | -1 |
| local_dataflow.rb:50:22:50:22 | 4 | local_dataflow.rb:50:18:50:22 | ... < ... | 0 |
| local_dataflow.rb:51:20:51:20 | x | local_dataflow.rb:51:20:51:24 | ... < ... | -1 |
| local_dataflow.rb:51:24:51:24 | 9 | local_dataflow.rb:51:20:51:24 | ... < ... | 0 |
| local_dataflow.rb:55:1:55:14 | self | local_dataflow.rb:55:1:55:14 | call to foo | -1 |
| local_dataflow.rb:55:5:55:13 | Array | local_dataflow.rb:55:5:55:13 | call to [] | -1 |
| local_dataflow.rb:55:5:55:13 | call to [] | local_dataflow.rb:55:1:55:14 | call to foo | 0 |
| local_dataflow.rb:55:6:55:6 | 1 | local_dataflow.rb:55:5:55:13 | call to [] | 0 |
| local_dataflow.rb:55:9:55:9 | 2 | local_dataflow.rb:55:5:55:13 | call to [] | 1 |
| local_dataflow.rb:55:12:55:12 | 3 | local_dataflow.rb:55:5:55:13 | call to [] | 2 |
| local_dataflow.rb:3:8:3:10 | self | local_dataflow.rb:3:8:3:10 | call to p | self |
| local_dataflow.rb:3:10:3:10 | a | local_dataflow.rb:3:8:3:10 | call to p | position 0 |
| local_dataflow.rb:6:8:6:8 | a | local_dataflow.rb:6:10:6:11 | ... + ... | self |
| local_dataflow.rb:6:13:6:13 | b | local_dataflow.rb:6:10:6:11 | ... + ... | position 0 |
| local_dataflow.rb:9:9:9:15 | Array | local_dataflow.rb:9:9:9:15 | call to [] | self |
| local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | position 0 |
| local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | position 1 |
| local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | position 2 |
| local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | block |
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | self |
| local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | self |
| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:12:3:12:5 | call to p | self |
| local_dataflow.rb:12:5:12:5 | x | local_dataflow.rb:12:3:12:5 | call to p | position 0 |
| local_dataflow.rb:15:1:17:3 | { ... } | local_dataflow.rb:15:1:17:3 | call to each | block |
| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | call to each | self |
| local_dataflow.rb:19:1:21:3 | { ... } | local_dataflow.rb:19:1:21:3 | call to each | block |
| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | call to each | self |
| local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... | self |
| local_dataflow.rb:20:10:20:10 | 1 | local_dataflow.rb:20:6:20:10 | ... > ... | position 0 |
| local_dataflow.rb:35:6:35:6 | x | local_dataflow.rb:35:6:35:11 | ... == ... | self |
| local_dataflow.rb:35:11:35:11 | 4 | local_dataflow.rb:35:6:35:11 | ... == ... | position 0 |
| local_dataflow.rb:42:6:42:6 | x | local_dataflow.rb:42:6:42:11 | ... == ... | self |
| local_dataflow.rb:42:11:42:11 | 4 | local_dataflow.rb:42:6:42:11 | ... == ... | position 0 |
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:49:1:53:3 | call to m | self |
| local_dataflow.rb:49:3:53:3 | do ... end | local_dataflow.rb:49:1:53:3 | call to m | block |
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | self |
| local_dataflow.rb:50:22:50:22 | 4 | local_dataflow.rb:50:18:50:22 | ... < ... | position 0 |
| local_dataflow.rb:51:20:51:20 | x | local_dataflow.rb:51:20:51:24 | ... < ... | self |
| local_dataflow.rb:51:24:51:24 | 9 | local_dataflow.rb:51:20:51:24 | ... < ... | position 0 |
| local_dataflow.rb:55:1:55:14 | self | local_dataflow.rb:55:1:55:14 | call to foo | self |
| local_dataflow.rb:55:5:55:13 | Array | local_dataflow.rb:55:5:55:13 | call to [] | self |
| local_dataflow.rb:55:5:55:13 | call to [] | local_dataflow.rb:55:1:55:14 | call to foo | position 0 |
| local_dataflow.rb:55:6:55:6 | 1 | local_dataflow.rb:55:5:55:13 | call to [] | position 0 |
| local_dataflow.rb:55:9:55:9 | 2 | local_dataflow.rb:55:5:55:13 | call to [] | position 1 |
| local_dataflow.rb:55:12:55:12 | 3 | local_dataflow.rb:55:5:55:13 | call to [] | position 2 |

View File

@@ -4,4 +4,6 @@ import codeql.ruby.dataflow.internal.DataFlowDispatch
query predicate ret(ReturningNode node) { any() }
query predicate arg(ArgumentNode n, DataFlowCall call, int pos) { n.argumentOf(call, pos) }
query predicate arg(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
n.argumentOf(call, pos)
}

View File

@@ -56,3 +56,23 @@ foo([1, 2, 3])
def foo x
end
def test_case x
y = case x
when 1 then 3
when 2 then x
when 3
x
else
x
end
z = case x
in 1 then 4
in 2 then x
in 3
x
else
x
end
end

View File

@@ -0,0 +1,35 @@
failures
edges
| params_flow.rb:9:16:9:17 | p1 : | params_flow.rb:10:10:10:11 | p1 |
| params_flow.rb:9:20:9:21 | p2 : | params_flow.rb:11:10:11:11 | p2 |
| params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:9:16:9:17 | p1 : |
| params_flow.rb:14:22:14:29 | call to taint : | params_flow.rb:9:20:9:21 | p2 : |
| params_flow.rb:16:13:16:14 | p1 : | params_flow.rb:17:10:17:11 | p1 |
| params_flow.rb:16:18:16:19 | p2 : | params_flow.rb:18:10:18:11 | p2 |
| params_flow.rb:21:13:21:20 | call to taint : | params_flow.rb:16:13:16:14 | p1 : |
| params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
| params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
| params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:16:13:16:14 | p1 : |
nodes
| params_flow.rb:9:16:9:17 | p1 : | semmle.label | p1 : |
| params_flow.rb:9:20:9:21 | p2 : | semmle.label | p2 : |
| params_flow.rb:10:10:10:11 | p1 | semmle.label | p1 |
| params_flow.rb:11:10:11:11 | p2 | semmle.label | p2 |
| params_flow.rb:14:12:14:19 | call to taint : | semmle.label | call to taint : |
| params_flow.rb:14:22:14:29 | call to taint : | semmle.label | call to taint : |
| params_flow.rb:16:13:16:14 | p1 : | semmle.label | p1 : |
| params_flow.rb:16:18:16:19 | p2 : | semmle.label | p2 : |
| params_flow.rb:17:10:17:11 | p1 | semmle.label | p1 |
| params_flow.rb:18:10:18:11 | p2 | semmle.label | p2 |
| params_flow.rb:21:13:21:20 | call to taint : | semmle.label | call to taint : |
| params_flow.rb:21:27:21:34 | call to taint : | semmle.label | call to taint : |
| params_flow.rb:22:13:22:20 | call to taint : | semmle.label | call to taint : |
| params_flow.rb:22:27:22:34 | call to taint : | semmle.label | call to taint : |
subpaths
#select
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:14:12:14:19 | call to taint : | call to taint : |
| params_flow.rb:11:10:11:11 | p2 | params_flow.rb:14:22:14:29 | call to taint : | params_flow.rb:11:10:11:11 | p2 | $@ | params_flow.rb:14:22:14:29 | call to taint : | call to taint : |
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:21:13:21:20 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:21:13:21:20 | call to taint : | call to taint : |
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:22:27:22:34 | call to taint : | call to taint : |
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:21:27:21:34 | call to taint : | call to taint : |
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:22:13:22:20 | call to taint : | call to taint : |

View File

@@ -0,0 +1,15 @@
/**
* @kind path-problem
*/
import ruby
import TestUtilities.InlineFlowTest
import PathGraph
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() { none() }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf
where conf.hasFlowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()

View File

@@ -0,0 +1,22 @@
def taint x
x
end
def sink x
puts x
end
def positional(p1, p2)
sink p1 # $ hasValueFlow=1
sink p2 # $ hasValueFlow=2
end
positional(taint(1), taint(2))
def keyword(p1:, p2:)
sink p1 # $ hasValueFlow=3 $ hasValueFlow=6
sink p2 # $ hasValueFlow=4 $ hasValueFlow=5
end
keyword(p1: taint(3), p2: taint(4))
keyword(p2: taint(5), p1: taint(6))

View File

@@ -2,7 +2,7 @@ actionControllerControllerClasses
| ActiveRecordInjection.rb:27:1:58:3 | FooController |
| ActiveRecordInjection.rb:60:1:90:3 | BarController |
| ActiveRecordInjection.rb:92:1:96:3 | BazController |
| app/controllers/foo/bars_controller.rb:3:1:25:3 | BarsController |
| app/controllers/foo/bars_controller.rb:3:1:31:3 | BarsController |
actionControllerActionMethods
| ActiveRecordInjection.rb:32:3:57:5 | some_request_handler |
| ActiveRecordInjection.rb:61:3:69:5 | some_other_request_handler |
@@ -57,8 +57,8 @@ redirectToCalls
| app/controllers/foo/bars_controller.rb:17:5:17:30 | call to redirect_to |
actionControllerHelperMethods
getAssociatedControllerClasses
| app/controllers/foo/bars_controller.rb:3:1:25: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:25:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
| app/controllers/foo/bars_controller.rb:3:1:31: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:31:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
controllerTemplateFiles
| app/controllers/foo/bars_controller.rb:3:1:25: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:25:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
| app/controllers/foo/bars_controller.rb:3:1:31: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:31:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |

View File

@@ -14,6 +14,7 @@ rawCalls
renderCalls
| app/controllers/foo/bars_controller.rb:6:5:6:37 | call to render |
| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render |
| app/controllers/foo/bars_controller.rb:29:5:29:17 | call to render |
| app/views/foo/bars/show.html.erb:31:5:31:89 | call to render |
renderToCalls
| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string |

View File

@@ -0,0 +1,76 @@
require 'logger'
class LoggerTest
@@cls_logger = Logger.new STDERR
@@cls_logger.progname = "LoggerTest"
def init_logger
if @logger == nil
@logger = Logger.new STDOUT
end
end
def debug_log(msg)
init_logger
@logger.debug msg
end
def error_log(msg)
init_logger
@logger.error do
msg + "!"
end
end
def fatal_log(msg)
init_logger
@logger.fatal msg
end
def warn_log(msg)
init_logger
@logger.warn msg
end
def unknown_log(msg)
init_logger
@logger.unknown("unknown prog") { msg }
end
def info_log(msg)
init_logger
@logger.info do
if msg.size > 100
msg[0..91] + "..." + msg[-5..msg.size]
else
msg
end
end
end
def push_log(msg)
logger = Logger.new STDERR
logger_alias = logger
logger_alias << ("test message: " + msg)
end
def add_log(msg)
@@cls_logger.add(Logger::INFO) { "block" }
# Includes both progname and block return if 'message' is 'nil'
@@cls_logger.add(Logger::INFO, nil, "progname1") { "block" }
# block return value is ignored if `message` is specified
@@cls_logger.add(Logger::WARN, "message1") { "not logged" }
@@cls_logger.add(Logger::WARN, "message2", "progname2") { "not logged" }
end
def log_log(msg)
@@cls_logger.log(Logger::INFO) { "block" }
# Includes both progname and block return if 'message' is 'nil'
@@cls_logger.log(Logger::INFO, nil, "progname1") { "block" }
# block return value is ignored if `message` is specified
@@cls_logger.log(Logger::WARN, "message1") { "not logged" }
@@cls_logger.log(Logger::WARN, "message2", "progname2") { "not logged" }
end
end

View File

@@ -69,3 +69,27 @@ classEvalCallCodeExecutions
| Eval.rb:25:1:25:47 | call to class_eval | Eval.rb:25:16:25:32 | "def foo; 1; end" |
moduleEvalCallCodeExecutions
| Eval.rb:26:1:26:54 | call to module_eval | Eval.rb:26:17:26:33 | "def bar; 1; end" |
loggerLoggingCallInputs
| Logging.rb:5:3:5:23 | call to progname= | Logging.rb:5:27:5:38 | "LoggerTest" |
| Logging.rb:15:5:15:21 | call to debug | Logging.rb:15:19:15:21 | msg |
| Logging.rb:20:5:22:7 | call to error | Logging.rb:21:7:21:15 | ... + ... |
| Logging.rb:27:5:27:21 | call to fatal | Logging.rb:27:19:27:21 | msg |
| Logging.rb:32:5:32:20 | call to warn | Logging.rb:32:18:32:20 | msg |
| Logging.rb:37:5:37:43 | call to unknown | Logging.rb:37:21:37:34 | "unknown prog" |
| Logging.rb:37:5:37:43 | call to unknown | Logging.rb:37:39:37:41 | msg |
| Logging.rb:42:5:48:7 | call to info | Logging.rb:43:7:47:9 | if ... |
| Logging.rb:54:5:54:44 | ... << ... | Logging.rb:54:21:54:44 | ( ... ) |
| Logging.rb:58:5:58:46 | call to add | Logging.rb:58:38:58:44 | "block" |
| Logging.rb:60:5:60:64 | call to add | Logging.rb:60:36:60:38 | nil |
| Logging.rb:60:5:60:64 | call to add | Logging.rb:60:41:60:51 | "progname1" |
| Logging.rb:60:5:60:64 | call to add | Logging.rb:60:56:60:62 | "block" |
| Logging.rb:63:5:63:63 | call to add | Logging.rb:63:36:63:45 | "message1" |
| Logging.rb:64:5:64:76 | call to add | Logging.rb:64:36:64:45 | "message2" |
| Logging.rb:64:5:64:76 | call to add | Logging.rb:64:48:64:58 | "progname2" |
| Logging.rb:68:5:68:46 | call to log | Logging.rb:68:38:68:44 | "block" |
| Logging.rb:70:5:70:64 | call to log | Logging.rb:70:36:70:38 | nil |
| Logging.rb:70:5:70:64 | call to log | Logging.rb:70:41:70:51 | "progname1" |
| Logging.rb:70:5:70:64 | call to log | Logging.rb:70:56:70:62 | "block" |
| Logging.rb:73:5:73:63 | call to log | Logging.rb:73:36:73:45 | "message1" |
| Logging.rb:74:5:74:76 | call to log | Logging.rb:74:36:74:45 | "message2" |
| Logging.rb:74:5:74:76 | call to log | Logging.rb:74:48:74:58 | "progname2" |

View File

@@ -30,3 +30,5 @@ query DataFlow::Node classEvalCallCodeExecutions(ClassEvalCallCodeExecution e) {
query DataFlow::Node moduleEvalCallCodeExecutions(ModuleEvalCallCodeExecution e) {
result = e.getCode()
}
query DataFlow::Node loggerLoggingCallInputs(LoggerLoggingCall c) { result = c.getAnInput() }

View File

@@ -22,4 +22,10 @@ class BarsController < ApplicationController
dt = params[:text]
render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" }
end
private
def unreachable_action
render "show"
end
end

View File

@@ -13,6 +13,7 @@ calls.rb:
# 97| Object
#-----| include -> Kernel
#-----| super -> BasicObject
#-----| prepend -> A
# 106| Array
#-----| super -> Object
@@ -49,12 +50,10 @@ calls.rb:
# 15| M
private.rb:
# 1| C
# 29| C
#-----| super -> Object
#-----| include -> M
calls.rb:
# 51| D
#-----| super -> C
@@ -66,6 +65,8 @@ calls.rb:
# 150| A
#-----| super -> S
#-----| super -> B
#-----| prepend -> A::B
# 155| B
#-----| super -> S
@@ -110,6 +111,13 @@ modules.rb:
# 115| XX
private.rb:
# 1| E
#-----| super -> Object
# 42| F
modules.rb:
# 5| Foo::Bar
# 19| Foo::ClassInFoo
@@ -134,6 +142,14 @@ modules.rb:
# 71| Test::Foo2::Foo2
modules_rec.rb:
# 1| B::A
#-----| super -> Object
# 4| A::B
#-----| super -> Object
modules.rb:
# 108| MM::MM
# 49| Foo::Bar::ClassInAnotherDefinitionOfFooBar

View File

@@ -75,16 +75,21 @@ getTarget
| modules.rb:90:24:90:36 | call to prepend | calls.rb:93:5:93:20 | prepend |
| modules.rb:96:3:96:14 | call to include | calls.rb:92:5:92:20 | include |
| modules.rb:102:3:102:16 | call to prepend | calls.rb:93:5:93:20 | prepend |
| modules_rec.rb:8:3:8:11 | call to prepend | calls.rb:93:5:93:20 | prepend |
| modules_rec.rb:11:1:11:9 | call to prepend | calls.rb:93:5:93:20 | prepend |
| private.rb:2:3:3:5 | call to private | calls.rb:94:5:94:20 | private |
| private.rb:10:3:10:19 | call to private | calls.rb:94:5:94:20 | private |
| private.rb:12:3:12:9 | call to private | calls.rb:94:5:94:20 | private |
| private.rb:24:1:24:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:25:1:25:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:26:1:26:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:27:1:27:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:28:1:28:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:28:1:28:12 | call to public | private.rb:5:3:6:5 | public |
| private.rb:30:1:30:15 | call to private_on_main | private.rb:21:1:22:3 | private_on_main |
| private.rb:34:1:34:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:35:1:35:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:36:1:36:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:37:1:37:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:38:1:38:5 | call to new | calls.rb:99:5:99:16 | new |
| private.rb:38:1:38:12 | call to public | private.rb:5:3:6:5 | public |
| private.rb:40:1:40:15 | call to private_on_main | private.rb:31:1:32:3 | private_on_main |
| private.rb:43:3:44:5 | call to private | calls.rb:94:5:94:20 | private |
| private.rb:51:3:51:19 | call to private | calls.rb:94:5:94:20 | private |
| private.rb:53:3:53:9 | call to private | calls.rb:94:5:94:20 | private |
unresolvedCall
| calls.rb:19:5:19:14 | call to instance_m |
| calls.rb:20:5:20:19 | call to instance_m |
@@ -110,10 +115,12 @@ unresolvedCall
| hello.rb:20:16:20:26 | ... + ... |
| hello.rb:20:16:20:34 | ... + ... |
| hello.rb:20:16:20:40 | ... + ... |
| private.rb:24:1:24:14 | call to private1 |
| private.rb:25:1:25:14 | call to private2 |
| private.rb:26:1:26:14 | call to private3 |
| private.rb:27:1:27:14 | call to private4 |
| private.rb:23:3:24:5 | call to private_class_method |
| private.rb:28:3:28:32 | call to private_class_method |
| private.rb:34:1:34:14 | call to private1 |
| private.rb:35:1:35:14 | call to private2 |
| private.rb:36:1:36:14 | call to private3 |
| private.rb:37:1:37:14 | call to private4 |
privateMethod
| calls.rb:1:1:3:3 | foo |
| calls.rb:62:1:65:3 | optional_arg |
@@ -126,4 +133,10 @@ privateMethod
| private.rb:8:3:9:5 | private2 |
| private.rb:14:3:15:5 | private3 |
| private.rb:17:3:18:5 | private4 |
| private.rb:21:1:22:3 | private_on_main |
| private.rb:23:24:24:5 | private5 |
| private.rb:26:3:27:5 | private6 |
| private.rb:31:1:32:3 | private_on_main |
| private.rb:43:11:44:5 | private1 |
| private.rb:49:3:50:5 | private2 |
| private.rb:55:3:56:5 | private3 |
| private.rb:58:3:59:5 | private4 |

View File

@@ -4,4 +4,4 @@ query Callable getTarget(Call call) { result = call.getATarget() }
query predicate unresolvedCall(Call call) { not exists(call.getATarget()) }
query predicate privateMethod(Method m) { m.isPrivate() }
query predicate privateMethod(MethodBase m) { m.isPrivate() }

View File

@@ -1,5 +1,6 @@
getMethod
| calls.rb:15:1:24:3 | M | instance_m | calls.rb:16:5:16:23 | instance_m |
| calls.rb:29:1:44:3 | C | baz | calls.rb:37:5:43:7 | baz |
| calls.rb:51:1:55:3 | D | baz | calls.rb:52:5:54:7 | baz |
| calls.rb:77:1:80:3 | Integer | abs | calls.rb:79:5:79:16 | abs |
| calls.rb:77:1:80:3 | Integer | bit_length | calls.rb:78:5:78:23 | bit_length |
@@ -17,7 +18,7 @@ getMethod
| calls.rb:97:1:100:3 | Object | new | calls.rb:99:5:99:16 | new |
| calls.rb:97:1:100:3 | Object | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:97:1:100:3 | Object | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:21:1:22:3 | private_on_main |
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:31:1:32:3 | private_on_main |
| calls.rb:102:1:104:3 | Hash | [] | calls.rb:103:5:103:15 | [] |
| calls.rb:106:1:117:3 | Array | [] | calls.rb:107:3:107:13 | [] |
| calls.rb:106:1:117:3 | Array | foreach | calls.rb:110:3:116:5 | foreach |
@@ -35,13 +36,28 @@ getMethod
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |
| private.rb:1:1:19:3 | C | baz | calls.rb:37:5:43:7 | baz |
| private.rb:1:1:19:3 | C | private2 | private.rb:8:3:9:5 | private2 |
| private.rb:1:1:19:3 | C | private3 | private.rb:14:3:15:5 | private3 |
| private.rb:1:1:19:3 | C | private4 | private.rb:17:3:18:5 | private4 |
| private.rb:1:1:19:3 | C | public | private.rb:5:3:6:5 | public |
| private.rb:1:1:29:3 | E | private2 | private.rb:8:3:9:5 | private2 |
| private.rb:1:1:29:3 | E | private3 | private.rb:14:3:15:5 | private3 |
| private.rb:1:1:29:3 | E | private4 | private.rb:17:3:18:5 | private4 |
| private.rb:1:1:29:3 | E | public | private.rb:5:3:6:5 | public |
| private.rb:42:1:60:3 | F | private2 | private.rb:49:3:50:5 | private2 |
| private.rb:42:1:60:3 | F | private3 | private.rb:55:3:56:5 | private3 |
| private.rb:42:1:60:3 | F | private4 | private.rb:58:3:59:5 | private4 |
| private.rb:42:1:60:3 | F | public | private.rb:46:3:47:5 | public |
lookupMethod
| calls.rb:15:1:24:3 | M | instance_m | calls.rb:16:5:16:23 | instance_m |
| calls.rb:29:1:44:3 | C | baz | calls.rb:37:5:43:7 | baz |
| calls.rb:29:1:44:3 | C | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:29:1:44:3 | C | foo | calls.rb:1:1:3:3 | foo |
| calls.rb:29:1:44:3 | C | foo | calls.rb:71:1:75:3 | foo |
| calls.rb:29:1:44:3 | C | funny | calls.rb:119:1:121:3 | funny |
| calls.rb:29:1:44:3 | C | indirect | calls.rb:137:1:139:3 | indirect |
| calls.rb:29:1:44:3 | C | instance_m | calls.rb:16:5:16:23 | instance_m |
| calls.rb:29:1:44:3 | C | new | calls.rb:99:5:99:16 | new |
| calls.rb:29:1:44:3 | C | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:29:1:44:3 | C | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:29:1:44:3 | C | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:29:1:44:3 | C | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:51:1:55:3 | D | baz | calls.rb:52:5:54:7 | baz |
| calls.rb:51:1:55:3 | D | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:51:1:55:3 | D | foo | calls.rb:1:1:3:3 | foo |
@@ -51,16 +67,14 @@ lookupMethod
| calls.rb:51:1:55:3 | D | instance_m | calls.rb:16:5:16:23 | instance_m |
| calls.rb:51:1:55:3 | D | new | calls.rb:99:5:99:16 | new |
| calls.rb:51:1:55:3 | D | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:51:1:55:3 | D | private2 | private.rb:8:3:9:5 | private2 |
| calls.rb:51:1:55:3 | D | private3 | private.rb:14:3:15:5 | private3 |
| calls.rb:51:1:55:3 | D | private4 | private.rb:17:3:18:5 | private4 |
| calls.rb:51:1:55:3 | D | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:51:1:55:3 | D | public | private.rb:5:3:6:5 | public |
| calls.rb:51:1:55:3 | D | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:51:1:55:3 | D | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:77:1:80:3 | Integer | abs | calls.rb:79:5:79:16 | abs |
| calls.rb:77:1:80:3 | Integer | bit_length | calls.rb:78:5:78:23 | bit_length |
| calls.rb:77:1:80:3 | Integer | new | calls.rb:99:5:99:16 | new |
| calls.rb:77:1:80:3 | Integer | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:77:1:80:3 | Integer | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:82:1:84:3 | String | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:82:1:84:3 | String | capitalize | calls.rb:83:5:83:23 | capitalize |
| calls.rb:82:1:84:3 | String | foo | calls.rb:1:1:3:3 | foo |
@@ -71,6 +85,7 @@ lookupMethod
| calls.rb:82:1:84:3 | String | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:82:1:84:3 | String | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:82:1:84:3 | String | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:82:1:84:3 | String | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:86:1:88:3 | Kernel | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:90:1:95:3 | Module | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:90:1:95:3 | Module | foo | calls.rb:1:1:3:3 | foo |
@@ -85,6 +100,7 @@ lookupMethod
| calls.rb:90:1:95:3 | Module | private | calls.rb:94:5:94:20 | private |
| calls.rb:90:1:95:3 | Module | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:90:1:95:3 | Module | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:90:1:95:3 | Module | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:97:1:100:3 | Object | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:97:1:100:3 | Object | foo | calls.rb:1:1:3:3 | foo |
| calls.rb:97:1:100:3 | Object | foo | calls.rb:71:1:75:3 | foo |
@@ -93,8 +109,9 @@ lookupMethod
| calls.rb:97:1:100:3 | Object | new | calls.rb:99:5:99:16 | new |
| calls.rb:97:1:100:3 | Object | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:97:1:100:3 | Object | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:21:1:22:3 | private_on_main |
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:31:1:32:3 | private_on_main |
| calls.rb:97:1:100:3 | Object | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:97:1:100:3 | Object | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:102:1:104:3 | Hash | [] | calls.rb:103:5:103:15 | [] |
| calls.rb:102:1:104:3 | Hash | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:102:1:104:3 | Hash | foo | calls.rb:1:1:3:3 | foo |
@@ -105,6 +122,7 @@ lookupMethod
| calls.rb:102:1:104:3 | Hash | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:102:1:104:3 | Hash | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:102:1:104:3 | Hash | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:102:1:104:3 | Hash | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:106:1:117:3 | Array | [] | calls.rb:107:3:107:13 | [] |
| calls.rb:106:1:117:3 | Array | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:106:1:117:3 | Array | foo | calls.rb:1:1:3:3 | foo |
@@ -117,6 +135,7 @@ lookupMethod
| calls.rb:106:1:117:3 | Array | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| calls.rb:106:1:117:3 | Array | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:106:1:117:3 | Array | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:106:1:117:3 | Array | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:144:1:148:3 | S | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:144:1:148:3 | S | foo | calls.rb:1:1:3:3 | foo |
| calls.rb:144:1:148:3 | S | foo | calls.rb:71:1:75:3 | foo |
@@ -127,6 +146,7 @@ lookupMethod
| calls.rb:144:1:148:3 | S | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| calls.rb:144:1:148:3 | S | puts | calls.rb:87:5:87:17 | puts |
| calls.rb:144:1:148:3 | S | s_method | calls.rb:145:5:147:7 | s_method |
| calls.rb:144:1:148:3 | S | to_s | calls.rb:151:5:152:7 | to_s |
| calls.rb:150:1:153:3 | A | call_block | calls.rb:67:1:69:3 | call_block |
| calls.rb:150:1:153:3 | A | foo | calls.rb:1:1:3:3 | foo |
| calls.rb:150:1:153:3 | A | foo | calls.rb:71:1:75:3 | foo |
@@ -155,31 +175,41 @@ lookupMethod
| file://:0:0:0:0 | Class | prepend | calls.rb:93:5:93:20 | prepend |
| file://:0:0:0:0 | Class | private | calls.rb:94:5:94:20 | private |
| file://:0:0:0:0 | Class | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | Class | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | Complex | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | Complex | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | Complex | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | FalseClass | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | FalseClass | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | FalseClass | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | Float | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | Float | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | Float | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | NilClass | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | NilClass | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | NilClass | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | Numeric | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | Numeric | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | Numeric | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | Rational | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | Rational | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | Rational | to_s | calls.rb:151:5:152:7 | to_s |
| file://:0:0:0:0 | TrueClass | new | calls.rb:99:5:99:16 | new |
| file://:0:0:0:0 | TrueClass | puts | calls.rb:87:5:87:17 | puts |
| file://:0:0:0:0 | TrueClass | to_s | calls.rb:151:5:152:7 | to_s |
| 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 | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
| hello.rb:11:1:16:3 | Greeting | new | calls.rb:99:5:99:16 | new |
| hello.rb:11:1:16:3 | Greeting | puts | calls.rb:87:5:87:17 | puts |
| hello.rb:11:1:16:3 | Greeting | to_s | calls.rb:151:5:152:7 | to_s |
| hello.rb:11:1:16:3 | Greeting | world | hello.rb:5:5:7:7 | world |
| hello.rb:18:1:22:3 | HelloWorld | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:18:1:22:3 | HelloWorld | message | hello.rb:19:5:21:7 | message |
| hello.rb:18:1:22:3 | HelloWorld | new | calls.rb:99:5:99:16 | new |
| hello.rb:18:1:22:3 | HelloWorld | puts | calls.rb:87:5:87:17 | puts |
| hello.rb:18:1:22:3 | HelloWorld | to_s | calls.rb:151:5:152:7 | to_s |
| hello.rb:18:1:22:3 | HelloWorld | world | hello.rb:5:5:7:7 | world |
| modules.rb:4:1:24:3 | Foo | method_in_another_definition_of_foo | modules.rb:27:3:28:5 | method_in_another_definition_of_foo |
| modules.rb:4:1:24:3 | Foo | method_in_foo | modules.rb:16:3:17:5 | method_in_foo |
@@ -187,37 +217,48 @@ lookupMethod
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | new | calls.rb:99:5:99:16 | new |
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:19:3:20:5 | Foo::ClassInFoo | new | calls.rb:99:5:99:16 | new |
| modules.rb:19:3:20:5 | Foo::ClassInFoo | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:19:3:20:5 | Foo::ClassInFoo | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | new | calls.rb:99:5:99:16 | new |
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |
| modules.rb:37:1:46:3 | Bar | new | calls.rb:99:5:99:16 | new |
| modules.rb:37:1:46:3 | Bar | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:37:1:46:3 | Bar | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | new | calls.rb:99:5:99:16 | new |
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:66:5:67:7 | Test::Foo1::Bar | new | calls.rb:99:5:99:16 | new |
| modules.rb:66:5:67:7 | Test::Foo1::Bar | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:66:5:67:7 | Test::Foo1::Bar | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | new | calls.rb:99:5:99:16 | new |
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:112:1:113:3 | YY | new | calls.rb:99:5:99:16 | new |
| modules.rb:112:1:113:3 | YY | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:112:1:113:3 | YY | to_s | calls.rb:151:5:152:7 | to_s |
| modules.rb:116:7:117:9 | XX::YY | new | calls.rb:99:5:99:16 | new |
| modules.rb:116:7:117:9 | XX::YY | puts | calls.rb:87:5:87:17 | puts |
| private.rb:1:1:19:3 | C | baz | calls.rb:37:5:43:7 | baz |
| private.rb:1:1:19:3 | C | call_block | calls.rb:67:1:69:3 | call_block |
| private.rb:1:1:19:3 | C | foo | calls.rb:1:1:3:3 | foo |
| private.rb:1:1:19:3 | C | foo | calls.rb:71:1:75:3 | foo |
| private.rb:1:1:19:3 | C | funny | calls.rb:119:1:121:3 | funny |
| private.rb:1:1:19:3 | C | indirect | calls.rb:137:1:139:3 | indirect |
| private.rb:1:1:19:3 | C | instance_m | calls.rb:16:5:16:23 | instance_m |
| private.rb:1:1:19:3 | C | new | calls.rb:99:5:99:16 | new |
| private.rb:1:1:19:3 | C | optional_arg | calls.rb:62:1:65:3 | optional_arg |
| private.rb:1:1:19:3 | C | private2 | private.rb:8:3:9:5 | private2 |
| private.rb:1:1:19:3 | C | private3 | private.rb:14:3:15:5 | private3 |
| private.rb:1:1:19:3 | C | private4 | private.rb:17:3:18:5 | private4 |
| private.rb:1:1:19:3 | C | private_on_main | calls.rb:164:1:165:3 | private_on_main |
| private.rb:1:1:19:3 | C | private_on_main | private.rb:21:1:22:3 | private_on_main |
| private.rb:1:1:19:3 | C | public | private.rb:5:3:6:5 | public |
| private.rb:1:1:19:3 | C | puts | calls.rb:87:5:87:17 | puts |
| modules.rb:116:7:117:9 | XX::YY | to_s | calls.rb:151:5:152:7 | to_s |
| modules_rec.rb:1:1:2:3 | B::A | new | calls.rb:99:5:99:16 | new |
| modules_rec.rb:1:1:2:3 | B::A | puts | calls.rb:87:5:87:17 | puts |
| modules_rec.rb:1:1:2:3 | B::A | to_s | calls.rb:151:5:152:7 | to_s |
| modules_rec.rb:4:1:5:3 | A::B | new | calls.rb:99:5:99:16 | new |
| modules_rec.rb:4:1:5:3 | A::B | puts | calls.rb:87:5:87:17 | puts |
| modules_rec.rb:4:1:5:3 | A::B | to_s | calls.rb:151:5:152:7 | to_s |
| private.rb:1:1:29:3 | E | new | calls.rb:99:5:99:16 | new |
| private.rb:1:1:29:3 | E | private2 | private.rb:8:3:9:5 | private2 |
| private.rb:1:1:29:3 | E | private3 | private.rb:14:3:15:5 | private3 |
| private.rb:1:1:29:3 | E | private4 | private.rb:17:3:18:5 | private4 |
| private.rb:1:1:29:3 | E | private_on_main | private.rb:31:1:32:3 | private_on_main |
| private.rb:1:1:29:3 | E | public | private.rb:5:3:6:5 | public |
| private.rb:1:1:29:3 | E | puts | calls.rb:87:5:87:17 | puts |
| private.rb:1:1:29:3 | E | to_s | calls.rb:151:5:152:7 | to_s |
| private.rb:42:1:60:3 | F | private2 | private.rb:49:3:50:5 | private2 |
| private.rb:42:1:60:3 | F | private3 | private.rb:55:3:56:5 | private3 |
| private.rb:42:1:60:3 | F | private4 | private.rb:58:3:59:5 | private4 |
| private.rb:42:1:60:3 | F | public | private.rb:46:3:47:5 | public |

View File

@@ -1,5 +1,6 @@
getModule
| calls.rb:15:1:24:3 | M |
| calls.rb:29:1:44:3 | C |
| calls.rb:51:1:55:3 | D |
| calls.rb:77:1:80:3 | Integer |
| calls.rb:82:1:84:3 | String |
@@ -55,9 +56,13 @@ getModule
| modules.rb:115:1:118:3 | XX |
| modules.rb:116:7:117:9 | XX::YY |
| modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz |
| private.rb:1:1:19:3 | C |
| modules_rec.rb:1:1:2:3 | B::A |
| modules_rec.rb:4:1:5:3 | A::B |
| private.rb:1:1:29:3 | E |
| private.rb:42:1:60:3 | F |
getADeclaration
| calls.rb:15:1:24:3 | M | calls.rb:15:1:24:3 | M |
| calls.rb:29:1:44:3 | C | calls.rb:29:1:44:3 | C |
| calls.rb:51:1:55:3 | D | calls.rb:51:1:55:3 | D |
| calls.rb:77:1:80:3 | Integer | calls.rb:77:1:80:3 | Integer |
| calls.rb:82:1:84:3 | String | calls.rb:82:1:84:3 | String |
@@ -66,12 +71,14 @@ getADeclaration
| calls.rb:97:1:100:3 | Object | calls.rb:1:1:167:16 | calls.rb |
| calls.rb:97:1:100:3 | Object | calls.rb:97:1:100:3 | Object |
| calls.rb:97:1:100:3 | Object | hello.rb:1:1:22:3 | hello.rb |
| calls.rb:97:1:100:3 | Object | modules.rb:1:1:122:1 | modules.rb |
| calls.rb:97:1:100:3 | Object | private.rb:1:1:30:15 | private.rb |
| calls.rb:97:1:100:3 | Object | modules.rb:1:1:121:4 | modules.rb |
| calls.rb:97:1:100:3 | Object | modules_rec.rb:1:1:11:10 | modules_rec.rb |
| calls.rb:97:1:100:3 | Object | private.rb:1:1:60:3 | private.rb |
| calls.rb:102:1:104:3 | Hash | calls.rb:102:1:104:3 | Hash |
| calls.rb:106:1:117:3 | Array | calls.rb:106:1:117:3 | Array |
| calls.rb:144:1:148:3 | S | calls.rb:144:1:148:3 | S |
| calls.rb:150:1:153:3 | A | calls.rb:150:1:153:3 | A |
| calls.rb:150:1:153:3 | A | modules_rec.rb:7:1:9:3 | A |
| calls.rb:155:1:158:3 | B | calls.rb:155:1:158:3 | B |
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:8:3 | EnglishWords |
| hello.rb:11:1:16:3 | Greeting | hello.rb:11:1:16:3 | Greeting |
@@ -109,10 +116,13 @@ getADeclaration
| modules.rb:115:1:118:3 | XX | modules.rb:115:1:118:3 | XX |
| modules.rb:116:7:117:9 | XX::YY | modules.rb:116:7:117:9 | YY |
| modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz | modules.rb:120:1:121:3 | Baz |
| private.rb:1:1:19:3 | C | calls.rb:29:1:44:3 | C |
| private.rb:1:1:19:3 | C | private.rb:1:1:19:3 | C |
| modules_rec.rb:1:1:2:3 | B::A | modules_rec.rb:1:1:2:3 | A |
| modules_rec.rb:4:1:5:3 | A::B | modules_rec.rb:4:1:5:3 | B |
| private.rb:1:1:29:3 | E | private.rb:1:1:29:3 | E |
| private.rb:42:1:60:3 | F | private.rb:42:1:60:3 | F |
getSuperClass
| calls.rb:51:1:55:3 | D | private.rb:1:1:19:3 | C |
| calls.rb:29:1:44:3 | C | calls.rb:97:1:100:3 | Object |
| calls.rb:51:1:55:3 | D | calls.rb:29:1:44:3 | C |
| calls.rb:77:1:80:3 | Integer | file://:0:0:0:0 | Numeric |
| calls.rb:82:1:84:3 | String | calls.rb:97:1:100:3 | Object |
| calls.rb:90:1:95:3 | Module | calls.rb:97:1:100:3 | Object |
@@ -121,6 +131,7 @@ getSuperClass
| calls.rb:106:1:117:3 | Array | calls.rb:97:1:100:3 | Object |
| calls.rb:144:1:148:3 | S | calls.rb:97:1:100:3 | Object |
| calls.rb:150:1:153:3 | A | calls.rb:144:1:148:3 | S |
| calls.rb:150:1:153:3 | A | calls.rb:155:1:158:3 | B |
| calls.rb:155:1:158:3 | B | calls.rb:144:1:148:3 | S |
| file://:0:0:0:0 | Class | calls.rb:90:1:95:3 | Module |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Numeric |
@@ -141,12 +152,130 @@ getSuperClass
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | calls.rb:97:1:100:3 | Object |
| modules.rb:112:1:113:3 | YY | calls.rb:97:1:100:3 | Object |
| modules.rb:116:7:117:9 | XX::YY | modules.rb:112:1:113:3 | YY |
| private.rb:1:1:19:3 | C | calls.rb:97:1:100:3 | Object |
| modules_rec.rb:1:1:2:3 | B::A | calls.rb:97:1:100:3 | Object |
| modules_rec.rb:4:1:5:3 | A::B | calls.rb:97:1:100:3 | Object |
| private.rb:1:1:29:3 | E | calls.rb:97:1:100:3 | Object |
getAPrependedModule
| calls.rb:97:1:100:3 | Object | calls.rb:150:1:153:3 | A |
| calls.rb:150:1:153:3 | A | modules_rec.rb:4:1:5:3 | A::B |
| modules.rb:101:1:105:3 | PrependTest | modules.rb:63:1:81:3 | Test |
getAnIncludedModule
| calls.rb:29:1:44:3 | C | calls.rb:15:1:24:3 | M |
| calls.rb:97:1:100:3 | Object | calls.rb:86:1:88:3 | Kernel |
| hello.rb:11:1:16:3 | Greeting | hello.rb:1:1:8:3 | EnglishWords |
| modules.rb:88:1:93:3 | IncludeTest | modules.rb:63:1:81:3 | Test |
| modules.rb:95:1:99:3 | IncludeTest2 | modules.rb:63:1:81:3 | Test |
| private.rb:1:1:19:3 | C | calls.rb:15:1:24:3 | M |
resolveConstantReadAccess
| calls.rb:26:1:26:1 | M | M |
| calls.rb:27:1:27:1 | M | M |
| calls.rb:30:13:30:13 | M | M |
| calls.rb:46:5:46:5 | C | C |
| calls.rb:51:11:51:11 | C | C |
| calls.rb:57:5:57:5 | D | D |
| calls.rb:72:11:72:14 | Hash | Hash |
| calls.rb:97:16:97:21 | Module | Module |
| calls.rb:98:13:98:18 | Kernel | Kernel |
| calls.rb:129:1:129:13 | Array | Array |
| calls.rb:131:1:131:7 | Array | Array |
| calls.rb:133:1:133:7 | Array | Array |
| calls.rb:135:1:135:8 | Array | Array |
| calls.rb:150:11:150:11 | S | S |
| calls.rb:155:11:155:11 | S | S |
| calls.rb:160:1:160:1 | S | S |
| calls.rb:161:1:161:1 | A | A |
| calls.rb:162:1:162:1 | B | B |
| hello.rb:12:13:12:24 | EnglishWords | EnglishWords |
| hello.rb:18:20:18:27 | Greeting | Greeting |
| modules.rb:48:8:48:10 | Foo | Foo |
| modules.rb:66:11:66:14 | Foo1 | Test::Foo1 |
| modules.rb:72:11:72:14 | Foo2 | Test::Foo2::Foo2 |
| modules.rb:77:12:77:17 | Object | Object |
| modules.rb:78:11:78:14 | Foo3 | Object |
| modules.rb:89:11:89:16 | Test | Test |
| modules.rb:90:3:90:8 | Object | Object |
| modules.rb:90:32:90:36 | Other | Other |
| modules.rb:91:10:91:13 | Foo1 | Test::Foo1 |
| modules.rb:96:11:96:14 | Test | Test |
| modules.rb:97:10:97:13 | Foo1 | Test::Foo1 |
| modules.rb:102:11:102:16 | Test | Test |
| modules.rb:103:10:103:13 | Foo2 | Test::Foo2 |
| modules.rb:108:10:108:11 | MM | MM |
| modules.rb:116:18:116:19 | YY | YY |
| modules.rb:120:8:120:11 | Test | Test |
| modules.rb:120:8:120:17 | Foo1 | Test::Foo1 |
| modules.rb:120:8:120:22 | Bar | Test::Foo1::Bar |
| modules_rec.rb:1:7:1:7 | B | B |
| modules_rec.rb:4:7:4:7 | A | A |
| modules_rec.rb:7:11:7:11 | B | B |
| modules_rec.rb:8:11:8:11 | B | A::B |
| modules_rec.rb:11:9:11:9 | A | A |
| private.rb:34:1:34:1 | E | E |
| private.rb:35:1:35:1 | E | E |
| private.rb:36:1:36:1 | E | E |
| private.rb:37:1:37:1 | E | E |
| private.rb:38:1:38:1 | E | E |
resolveConstantWriteAccess
| calls.rb:15:1:24:3 | M | M |
| calls.rb:29:1:44:3 | C | C |
| calls.rb:51:1:55:3 | D | D |
| calls.rb:77:1:80:3 | Integer | Integer |
| calls.rb:82:1:84:3 | String | String |
| calls.rb:86:1:88:3 | Kernel | Kernel |
| calls.rb:90:1:95:3 | Module | Module |
| calls.rb:97:1:100:3 | Object | Object |
| calls.rb:102:1:104:3 | Hash | Hash |
| calls.rb:106:1:117:3 | Array | Array |
| calls.rb:144:1:148:3 | S | S |
| calls.rb:150:1:153:3 | A | A |
| calls.rb:155:1:158:3 | B | B |
| hello.rb:1:1:8:3 | EnglishWords | EnglishWords |
| hello.rb:11:1:16:3 | Greeting | Greeting |
| hello.rb:18:1:22:3 | HelloWorld | HelloWorld |
| modules.rb:1:1:2:3 | Empty | Empty |
| modules.rb:4:1:24:3 | Foo | Foo |
| modules.rb:5:3:14:5 | Bar | Foo::Bar |
| modules.rb:6:5:7:7 | ClassInFooBar | Foo::Bar::ClassInFooBar |
| modules.rb:19:3:20:5 | ClassInFoo | Foo::ClassInFoo |
| modules.rb:26:1:35:3 | Foo | Foo |
| modules.rb:30:3:31:5 | ClassInAnotherDefinitionOfFoo | Foo::ClassInAnotherDefinitionOfFoo |
| modules.rb:37:1:46:3 | Bar | Bar |
| modules.rb:48:1:57:3 | Bar | Foo::Bar |
| modules.rb:49:3:50:5 | ClassInAnotherDefinitionOfFooBar | Foo::Bar::ClassInAnotherDefinitionOfFooBar |
| modules.rb:60:1:61:3 | MyModuleInGlobalScope | MyModuleInGlobalScope |
| modules.rb:63:1:81:3 | Test | Test |
| modules.rb:65:3:68:5 | Foo1 | Test::Foo1 |
| modules.rb:66:5:67:7 | Bar | Foo1::Bar |
| modules.rb:66:5:67:7 | Bar | Test::Foo1::Bar |
| modules.rb:70:3:74:5 | Foo2 | Test::Foo2 |
| modules.rb:71:5:71:19 | Foo2 | Test::Foo2::Foo2 |
| modules.rb:72:5:73:7 | Bar | Foo2::Bar |
| modules.rb:72:5:73:7 | Bar | Test::Foo2::Bar |
| modules.rb:72:5:73:7 | Bar | Test::Foo2::Foo2::Bar |
| modules.rb:76:3:80:5 | Foo3 | Test::Foo3 |
| modules.rb:77:5:77:8 | Foo3 | Test::Foo3::Foo3 |
| modules.rb:78:5:79:7 | Bar | Foo3::Bar |
| modules.rb:78:5:79:7 | Bar | Test::Foo3::Bar |
| modules.rb:78:5:79:7 | Bar | Test::Foo3::Foo3::Bar |
| modules.rb:83:1:86:3 | Other | Other |
| modules.rb:84:3:85:5 | Foo1 | Other::Foo1 |
| modules.rb:88:1:93:3 | IncludeTest | IncludeTest |
| modules.rb:91:3:92:5 | Y | Foo1::Y |
| modules.rb:91:3:92:5 | Y | Test::Foo1::Y |
| modules.rb:95:1:99:3 | IncludeTest2 | IncludeTest2 |
| modules.rb:97:3:98:5 | Z | Foo1::Z |
| modules.rb:97:3:98:5 | Z | Test::Foo1::Z |
| modules.rb:101:1:105:3 | PrependTest | PrependTest |
| modules.rb:103:3:104:5 | Y | Foo2::Y |
| modules.rb:103:3:104:5 | Y | Test::Foo2::Y |
| modules.rb:107:1:110:3 | MM | MM |
| modules.rb:108:3:109:5 | MM | MM::MM |
| modules.rb:108:3:109:5 | MM | MM::MM::MM |
| modules.rb:112:1:113:3 | YY | YY |
| modules.rb:115:1:118:3 | XX | XX |
| modules.rb:116:7:117:9 | YY | XX::YY |
| modules.rb:120:1:121:3 | Baz | Test::Foo1::Bar::Baz |
| modules_rec.rb:1:1:2:3 | A | B::A |
| modules_rec.rb:4:1:5:3 | B | A::B |
| modules_rec.rb:7:1:9:3 | A | A |
| private.rb:1:1:29:3 | E | E |
| private.rb:42:1:60:3 | F | F |

View File

@@ -1,4 +1,5 @@
import ruby
private import codeql.ruby.ast.internal.Module as Internal
query Module getModule() { any() }
@@ -9,3 +10,11 @@ query Module getSuperClass(Module m) { result = m.getSuperClass() }
query Module getAPrependedModule(Module m) { result = m.getAPrependedModule() }
query Module getAnIncludedModule(Module m) { result = m.getAnIncludedModule() }
query predicate resolveConstantReadAccess(ConstantReadAccess a, string s) {
Internal::TResolved(s) = Internal::resolveConstantReadAccess(a)
}
query predicate resolveConstantWriteAccess(ConstantWriteAccess c, string s) {
s = Internal::resolveConstantWriteAccess(c)
}

View File

@@ -119,4 +119,3 @@ end
module Test::Foo1::Bar::Baz
end

View File

@@ -0,0 +1,11 @@
class B::A
end
class A::B
end
class A < B
prepend B
end
prepend A

View File

@@ -1,4 +1,4 @@
class C
class E
private def private1
end
@@ -16,15 +16,45 @@ class C
def private4
end
def self.public2
end
private_class_method def self.private5
end
def self.private6
end
private_class_method :private6
end
def private_on_main
end
C.new.private1
C.new.private2
C.new.private3
C.new.private4
C.new.public
E.new.private1
E.new.private2
E.new.private3
E.new.private4
E.new.public
private_on_main
private_on_main
module F
private def private1
end
def public
end
def private2
end
private :private2
private
def private3
end
def private4
end
end

View File

@@ -48,11 +48,9 @@ calls.rb:
# 15| M
private.rb:
# 1| C
# 29| C
#-----| -> Object
calls.rb:
# 51| D
#-----| -> C
@@ -64,6 +62,7 @@ calls.rb:
# 150| A
#-----| -> S
#-----| -> B
# 155| B
#-----| -> S
@@ -104,6 +103,13 @@ modules.rb:
# 115| XX
private.rb:
# 1| E
#-----| -> Object
# 42| F
modules.rb:
# 5| Foo::Bar
# 19| Foo::ClassInFoo
@@ -128,6 +134,14 @@ modules.rb:
# 71| Test::Foo2::Foo2
modules_rec.rb:
# 1| B::A
#-----| -> Object
# 4| A::B
#-----| -> Object
modules.rb:
# 108| MM::MM
# 49| Foo::Bar::ClassInAnotherDefinitionOfFooBar

View File

@@ -0,0 +1,85 @@
weakHashingAlgorithms
| HAVEL128 |
| MD2 |
| MD4 |
| MD5 |
| PANAMA |
| RIPEMD |
| RIPEMD128 |
| RIPEMD160 |
| RIPEMD256 |
| RIPEMD320 |
| SHA0 |
| SHA1 |
strongHashingAlgorithms
| DSA |
| ECDSA256 |
| ECDSA384 |
| ECDSA512 |
| ED25519 |
| ES256 |
| ES384 |
| ES512 |
| SHA2 |
| SHA3 |
| SHA224 |
| SHA256 |
| SHA384 |
| SHA512 |
| SHA3224 |
| SHA3256 |
| SHA3384 |
| SHA3512 |
weakEncryptionAlgorithms
| 3DES |
| ARC2 |
| ARC4 |
| ARC5 |
| ARCFOUR |
| DES |
| DES3 |
| DESX |
| RC2 |
| RC4 |
| RC5 |
| TDEA |
| TRIPLEDEA |
| TRIPLEDES |
strongEncryptionAlgorithms
| AES |
| AES128 |
| AES192 |
| AES256 |
| AES512 |
| AES-128 |
| AES-192 |
| AES-256 |
| AES-512 |
| ARIA |
| BF |
| BLOWFISH |
| CAMELLIA |
| CAMELLIA128 |
| CAMELLIA192 |
| CAMELLIA256 |
| CAMELLIA-128 |
| CAMELLIA-192 |
| CAMELLIA-256 |
| CAST |
| CAST5 |
| CHACHA |
| ECIES |
| GOST |
| GOST89 |
| IDEA |
| RABBIT |
| RSA |
| SEED |
| SM4 |
weakPasswordHashingAlgorithms
| EVPKDF |
strongPasswordHashingAlgorithms
| ARGON2 |
| BCRYPT |
| PBKDF2 |
| SCRYPT |

View File

@@ -0,0 +1,14 @@
import ruby
import codeql.ruby.security.CryptoAlgorithms
query predicate weakHashingAlgorithms(HashingAlgorithm ha) { ha.isWeak() }
query predicate strongHashingAlgorithms(HashingAlgorithm ha) { not ha.isWeak() }
query predicate weakEncryptionAlgorithms(EncryptionAlgorithm ea) { ea.isWeak() }
query predicate strongEncryptionAlgorithms(EncryptionAlgorithm ea) { not ea.isWeak() }
query predicate weakPasswordHashingAlgorithms(PasswordHashingAlgorithm pha) { pha.isWeak() }
query predicate strongPasswordHashingAlgorithms(PasswordHashingAlgorithm pha) { not pha.isWeak() }

View File

@@ -0,0 +1,274 @@
weakOpenSSLCipherAlgorithms
| AES-128-CBC-HMAC-SHA1 |
| AES-128-CBC-HMAC-SHA1 |
| AES-128-ECB |
| AES-128-ECB |
| AES-192-ECB |
| AES-192-ECB |
| AES-256-CBC-HMAC-SHA1 |
| AES-256-CBC-HMAC-SHA1 |
| AES-256-ECB |
| AES-256-ECB |
| ARIA-128-ECB |
| ARIA-192-ECB |
| ARIA-256-ECB |
| BF-ECB |
| BF-ECB |
| CAMELLIA-128-ECB |
| CAMELLIA-128-ECB |
| CAMELLIA-192-ECB |
| CAMELLIA-192-ECB |
| CAMELLIA-256-ECB |
| CAMELLIA-256-ECB |
| CAST5-ECB |
| CAST5-ECB |
| DES-CBC |
| DES-CBC |
| DES-CBC |
| DES-CBC |
| DES-CFB |
| DES-CFB |
| DES-CFB1 |
| DES-CFB1 |
| DES-CFB8 |
| DES-CFB8 |
| DES-ECB |
| DES-ECB |
| DES-EDE |
| DES-EDE |
| DES-EDE3 |
| DES-EDE3 |
| DES-EDE3-CBC |
| DES-EDE3-CBC |
| DES-EDE3-CBC |
| DES-EDE3-CBC |
| DES-EDE3-CFB |
| DES-EDE3-CFB |
| DES-EDE3-CFB1 |
| DES-EDE3-CFB1 |
| DES-EDE3-CFB8 |
| DES-EDE3-CFB8 |
| DES-EDE3-ECB |
| DES-EDE3-OFB |
| DES-EDE3-OFB |
| DES-EDE-CBC |
| DES-EDE-CBC |
| DES-EDE-CFB |
| DES-EDE-CFB |
| DES-EDE-ECB |
| DES-EDE-OFB |
| DES-EDE-OFB |
| DES-OFB |
| DES-OFB |
| DESX-CBC |
| DESX-CBC |
| DESX-CBC |
| DESX-CBC |
| IDEA-ECB |
| IDEA-ECB |
| RC2-40 |
| RC2-40-CBC |
| RC2-40-CBC |
| RC2-64 |
| RC2-64-CBC |
| RC2-64-CBC |
| RC2-128 |
| RC2-CBC |
| RC2-CBC |
| RC2-CBC |
| RC2-CBC |
| RC2-CFB |
| RC2-CFB |
| RC2-ECB |
| RC2-ECB |
| RC2-OFB |
| RC2-OFB |
| RC4 |
| RC4 |
| RC4-40 |
| RC4-40 |
| RC4-HMAC-MD5 |
| RC4-HMAC-MD5 |
| SEED-ECB |
| SM4-ECB |
| SM4-ECB |
| gost89-ecb |
strongOpenSSLCipherAlgorithms
| AES-128-CBC |
| AES-128-CBC |
| AES-128-CBC |
| AES-128-CBC |
| AES-128-CBC-HMAC-SHA256 |
| AES-128-CFB |
| AES-128-CFB |
| AES-128-CFB1 |
| AES-128-CFB1 |
| AES-128-CFB8 |
| AES-128-CFB8 |
| AES-128-CTR |
| AES-128-CTR |
| AES-128-OCB |
| AES-128-OFB |
| AES-128-OFB |
| AES-128-XTS |
| AES-128-XTS |
| AES-192-CBC |
| AES-192-CBC |
| AES-192-CBC |
| AES-192-CBC |
| AES-192-CFB |
| AES-192-CFB |
| AES-192-CFB1 |
| AES-192-CFB1 |
| AES-192-CFB8 |
| AES-192-CFB8 |
| AES-192-CTR |
| AES-192-CTR |
| AES-192-OCB |
| AES-192-OFB |
| AES-192-OFB |
| AES-256-CBC |
| AES-256-CBC |
| AES-256-CBC |
| AES-256-CBC |
| AES-256-CBC-HMAC-SHA256 |
| AES-256-CFB |
| AES-256-CFB |
| AES-256-CFB1 |
| AES-256-CFB1 |
| AES-256-CFB8 |
| AES-256-CFB8 |
| AES-256-CTR |
| AES-256-CTR |
| AES-256-OCB |
| AES-256-OFB |
| AES-256-OFB |
| AES-256-XTS |
| AES-256-XTS |
| ARIA128 |
| ARIA192 |
| ARIA256 |
| ARIA-128-CBC |
| ARIA-128-CCM |
| ARIA-128-CFB |
| ARIA-128-CFB1 |
| ARIA-128-CFB8 |
| ARIA-128-CTR |
| ARIA-128-GCM |
| ARIA-128-OFB |
| ARIA-192-CBC |
| ARIA-192-CCM |
| ARIA-192-CFB |
| ARIA-192-CFB1 |
| ARIA-192-CFB8 |
| ARIA-192-CTR |
| ARIA-192-GCM |
| ARIA-192-OFB |
| ARIA-256-CBC |
| ARIA-256-CCM |
| ARIA-256-CFB |
| ARIA-256-CFB1 |
| ARIA-256-CFB8 |
| ARIA-256-CTR |
| ARIA-256-GCM |
| ARIA-256-OFB |
| BF-CBC |
| BF-CBC |
| BF-CBC |
| BF-CBC |
| BF-CBC |
| BF-CFB |
| BF-CFB |
| BF-OFB |
| BF-OFB |
| CAMELLIA-128-CBC |
| CAMELLIA-128-CBC |
| CAMELLIA-128-CBC |
| CAMELLIA-128-CBC |
| CAMELLIA-128-CFB |
| CAMELLIA-128-CFB |
| CAMELLIA-128-CFB1 |
| CAMELLIA-128-CFB1 |
| CAMELLIA-128-CFB8 |
| CAMELLIA-128-CFB8 |
| CAMELLIA-128-CTR |
| CAMELLIA-128-OFB |
| CAMELLIA-128-OFB |
| CAMELLIA-192-CBC |
| CAMELLIA-192-CBC |
| CAMELLIA-192-CBC |
| CAMELLIA-192-CBC |
| CAMELLIA-192-CFB |
| CAMELLIA-192-CFB |
| CAMELLIA-192-CFB1 |
| CAMELLIA-192-CFB1 |
| CAMELLIA-192-CFB8 |
| CAMELLIA-192-CFB8 |
| CAMELLIA-192-CTR |
| CAMELLIA-192-OFB |
| CAMELLIA-192-OFB |
| CAMELLIA-256-CBC |
| CAMELLIA-256-CBC |
| CAMELLIA-256-CBC |
| CAMELLIA-256-CBC |
| CAMELLIA-256-CFB |
| CAMELLIA-256-CFB |
| CAMELLIA-256-CFB1 |
| CAMELLIA-256-CFB1 |
| CAMELLIA-256-CFB8 |
| CAMELLIA-256-CFB8 |
| CAMELLIA-256-CTR |
| CAMELLIA-256-OFB |
| CAMELLIA-256-OFB |
| CAST5-CBC |
| CAST5-CBC |
| CAST5-CBC |
| CAST5-CBC |
| CAST5-CBC |
| CAST5-CBC |
| CAST5-CFB |
| CAST5-CFB |
| CAST5-OFB |
| CAST5-OFB |
| CHACHA20 |
| CHACHA20-POLY1305 |
| ChaCha |
| ChaCha |
| IDEA-CBC |
| IDEA-CBC |
| IDEA-CBC |
| IDEA-CBC |
| IDEA-CFB |
| IDEA-CFB |
| IDEA-OFB |
| IDEA-OFB |
| SEED |
| SEED-CBC |
| SEED-CFB |
| SEED-OFB |
| SM4-CBC |
| SM4-CBC |
| SM4-CBC |
| SM4-CBC |
| SM4-CFB |
| SM4-CFB |
| SM4-CTR |
| SM4-CTR |
| SM4-OFB |
| SM4-OFB |
| gost89 |
| gost89 |
| gost89-cnt |
| id-aes128-CCM |
| id-aes128-CCM |
| id-aes128-GCM |
| id-aes128-GCM |
| id-aes192-CCM |
| id-aes192-CCM |
| id-aes192-GCM |
| id-aes192-GCM |
| id-aes256-CCM |
| id-aes256-CCM |
| id-aes256-GCM |
| id-aes256-GCM |
missingOpenSSLCipherAlgorithms

View File

@@ -0,0 +1,11 @@
import ruby
import codeql.ruby.security.OpenSSL
query predicate weakOpenSSLCipherAlgorithms(OpenSSLCipher c) { c.isWeak() }
query predicate strongOpenSSLCipherAlgorithms(OpenSSLCipher c) { not c.isWeak() }
query predicate missingOpenSSLCipherAlgorithms(string name) {
Ciphers::isOpenSSLCipher(name) and
not exists(OpenSSLCipher c | c.getName() = name)
}

View File

@@ -23,6 +23,11 @@ parameterVariable
| parameters.rb:49:12:49:16 | (..., ...) | parameters.rb:49:13:49:13 | a |
| parameters.rb:49:12:49:16 | (..., ...) | parameters.rb:49:15:49:15 | b |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y |
| parameters.rb:59:19:59:27 | (..., ...) | parameters.rb:59:20:59:20 | a |
| parameters.rb:59:19:59:27 | (..., ...) | parameters.rb:59:23:59:23 | b |
| parameters.rb:59:19:59:27 | (..., ...) | parameters.rb:59:25:59:25 | c |
| parameters.rb:59:22:59:26 | (..., ...) | parameters.rb:59:23:59:23 | b |
| parameters.rb:59:22:59:26 | (..., ...) | parameters.rb:59:25:59:25 | c |
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x |
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x |
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b |

View File

@@ -56,3 +56,7 @@ x = 10
puts y
end
def tuples_nested((a,(b,c)))
puts "#{a} #{b} #{c}"
end

View File

@@ -29,7 +29,7 @@ definition
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self |
@@ -63,11 +63,15 @@ definition
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b |
| parameters.rb:53:1:53:6 | ... = ... | parameters.rb:53:1:53:1 | x |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:53:1:53:1 | x |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y |
| parameters.rb:54:19:54:23 | ... = ... | parameters.rb:53:1:53:1 | x |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self |
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a |
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a |
@@ -180,8 +184,8 @@ read
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
@@ -215,10 +219,14 @@ read
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self |
@@ -339,7 +347,7 @@ firstRead
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
@@ -371,9 +379,13 @@ firstRead
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
@@ -464,7 +476,7 @@ lastRead
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
@@ -496,9 +508,13 @@ lastRead
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
@@ -568,11 +584,11 @@ adjacentReads
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a |
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self | nested_scopes.rb:28:16:28:16 | self |
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:30:16:30:19 | self | nested_scopes.rb:32:11:32:16 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas |
| parameters.rb:25:1:28:3 | self (opt_param) | parameters.rb:25:1:28:3 | self | parameters.rb:26:3:26:11 | self | parameters.rb:27:3:27:11 | self |
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |

View File

@@ -73,9 +73,9 @@ variableAccess
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | do ... end |
| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end |
| parameters.rb:2:4:2:4 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end |
| parameters.rb:3:4:3:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:3:4:3:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:3:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | do ... end |
| parameters.rb:4:4:4:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:4:4:4:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:4:9:4:9 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end |
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza |
@@ -108,7 +108,7 @@ variableAccess
| parameters.rb:31:11:31:15 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | key_param |
| parameters.rb:31:20:31:25 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | key_param |
| parameters.rb:31:30:31:33 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | key_param |
| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:35:11:35:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | multi |
| parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | multi |
| parameters.rb:37:3:37:18 | self | parameters.rb:35:1:38:3 | self | parameters.rb:35:1:38:3 | multi |
@@ -127,13 +127,20 @@ variableAccess
| parameters.rb:50:3:50:18 | self | parameters.rb:49:1:51:3 | self | parameters.rb:49:1:51:3 | tuples |
| parameters.rb:50:11:50:11 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | tuples |
| parameters.rb:50:16:50:16 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | tuples |
| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | do ... end |
| parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:55:4:55:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:56:4:56:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:55:4:55:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:56:4:56:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:56:9:56:9 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | do ... end |
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:59:1:61:3 | tuples_nested |
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:59:1:61:3 | tuples_nested |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:59:1:61:3 | tuples_nested |
| parameters.rb:60:3:60:23 | self | parameters.rb:59:1:61:3 | self | parameters.rb:59:1:61:3 | tuples_nested |
| parameters.rb:60:11:60:11 | a | parameters.rb:59:20:59:20 | a | parameters.rb:59:1:61:3 | tuples_nested |
| parameters.rb:60:16:60:16 | b | parameters.rb:59:23:59:23 | b | parameters.rb:59:1:61:3 | tuples_nested |
| parameters.rb:60:21:60:21 | c | parameters.rb:59:25:59:25 | c | parameters.rb:59:1:61:3 | tuples_nested |
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | do ... end |
| scopes.rb:3:4:3:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
| scopes.rb:3:9:3:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
@@ -354,6 +361,9 @@ implicitWrite
| parameters.rb:49:13:49:13 | a |
| parameters.rb:49:15:49:15 | b |
| parameters.rb:54:14:54:14 | y |
| parameters.rb:59:20:59:20 | a |
| parameters.rb:59:23:59:23 | b |
| parameters.rb:59:25:59:25 | c |
| scopes.rb:2:14:2:14 | x |
| scopes.rb:9:14:9:14 | x |
| ssa.rb:1:7:1:7 | b |
@@ -452,6 +462,10 @@ readAccess
| parameters.rb:55:9:55:9 | x |
| parameters.rb:56:4:56:9 | self |
| parameters.rb:56:9:56:9 | y |
| parameters.rb:60:3:60:23 | self |
| parameters.rb:60:11:60:11 | a |
| parameters.rb:60:16:60:16 | b |
| parameters.rb:60:21:60:21 | c |
| scopes.rb:3:4:3:9 | self |
| scopes.rb:3:9:3:9 | self |
| scopes.rb:5:4:5:9 | self |

View File

@@ -56,7 +56,7 @@
| nested_scopes.rb:30:7:33:9 | self |
| nested_scopes.rb:31:11:31:11 | a |
| nested_scopes.rb:40:1:40:1 | d |
| parameters.rb:1:1:58:1 | self |
| parameters.rb:1:1:62:1 | self |
| parameters.rb:1:14:1:14 | x |
| parameters.rb:1:18:1:18 | y |
| parameters.rb:7:1:13:3 | self |
@@ -89,6 +89,10 @@
| parameters.rb:49:15:49:15 | b |
| parameters.rb:53:1:53:1 | x |
| parameters.rb:54:14:54:14 | y |
| parameters.rb:59:1:61:3 | self |
| parameters.rb:59:20:59:20 | a |
| parameters.rb:59:23:59:23 | b |
| parameters.rb:59:25:59:25 | c |
| scopes.rb:1:1:1:15 | self |
| scopes.rb:1:1:49:4 | self |
| scopes.rb:2:14:2:14 | x |

View File

@@ -32,7 +32,7 @@
| nested_scopes.rb:22:9:24:11 | show_a2 |
| nested_scopes.rb:27:7:29:9 | show |
| nested_scopes.rb:30:7:33:9 | class << ... |
| parameters.rb:1:1:58:1 | parameters.rb |
| parameters.rb:1:1:62:1 | parameters.rb |
| parameters.rb:1:9:5:3 | do ... end |
| parameters.rb:7:1:13:3 | order_pizza |
| parameters.rb:15:1:19:3 | print_map |
@@ -45,6 +45,7 @@
| parameters.rb:45:1:47:3 | dup_underscore |
| parameters.rb:49:1:51:3 | tuples |
| parameters.rb:54:9:57:3 | do ... end |
| parameters.rb:59:1:61:3 | tuples_nested |
| scopes.rb:1:1:1:15 | a |
| scopes.rb:1:1:49:4 | scopes.rb |
| scopes.rb:2:9:6:3 | do ... end |

View File

@@ -1,5 +1,6 @@
edges
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password |
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : | HardcodedCredentials.rb:1:33:1:36 | cert |
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | HardcodedCredentials.rb:1:23:1:30 | password |
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:18:19:18:72 | ... + ... : |
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:23:19:23:20 | pw : |
@@ -10,10 +11,12 @@ edges
| HardcodedCredentials.rb:43:57:43:70 | "abcdef123456" : | HardcodedCredentials.rb:43:46:43:53 | password |
nodes
| HardcodedCredentials.rb:1:23:1:30 | password | semmle.label | password |
| HardcodedCredentials.rb:1:33:1:36 | cert | semmle.label | cert |
| HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | semmle.label | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." |
| HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | semmle.label | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." |
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | semmle.label | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : |
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | semmle.label | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." |
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : | semmle.label | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : |
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | semmle.label | ... + ... : |
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | semmle.label | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : |
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | semmle.label | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : |
@@ -31,6 +34,7 @@ subpaths
| HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | Use of $@. | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | hardcoded credentials |
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | Use of $@. | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | hardcoded credentials |
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : | HardcodedCredentials.rb:1:33:1:36 | cert | Use of $@. | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | hardcoded credentials |
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | hardcoded credentials |
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | hardcoded credentials |
| HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | hardcoded credentials |

View File

@@ -0,0 +1,21 @@
edges
| ConditionalBypass.rb:3:13:3:18 | call to params : | ConditionalBypass.rb:6:8:6:12 | check |
| ConditionalBypass.rb:14:14:14:19 | call to params : | ConditionalBypass.rb:14:14:14:27 | ...[...] |
| ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:25:10:25:22 | ...[...] |
| ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:25:10:25:22 | ...[...] : |
| ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:27:8:27:8 | p |
| ConditionalBypass.rb:25:10:25:22 | ...[...] : | ConditionalBypass.rb:27:8:27:8 | p |
nodes
| ConditionalBypass.rb:3:13:3:18 | call to params : | semmle.label | call to params : |
| ConditionalBypass.rb:6:8:6:12 | check | semmle.label | check |
| ConditionalBypass.rb:14:14:14:19 | call to params : | semmle.label | call to params : |
| ConditionalBypass.rb:14:14:14:27 | ...[...] | semmle.label | ...[...] |
| ConditionalBypass.rb:25:10:25:15 | call to params : | semmle.label | call to params : |
| ConditionalBypass.rb:25:10:25:22 | ...[...] | semmle.label | ...[...] |
| ConditionalBypass.rb:25:10:25:22 | ...[...] : | semmle.label | ...[...] : |
| ConditionalBypass.rb:27:8:27:8 | p | semmle.label | p |
subpaths
#select
| ConditionalBypass.rb:6:8:6:12 | check | ConditionalBypass.rb:3:13:3:18 | call to params : | ConditionalBypass.rb:6:8:6:12 | check | This condition guards a sensitive $@, but $@ controls it. | ConditionalBypass.rb:8:7:8:29 | call to authenticate_user! | action | ConditionalBypass.rb:3:13:3:18 | call to params | a user-provided value |
| ConditionalBypass.rb:14:14:14:27 | ...[...] | ConditionalBypass.rb:14:14:14:19 | call to params : | ConditionalBypass.rb:14:14:14:27 | ...[...] | This condition guards a sensitive $@, but $@ controls it. | ConditionalBypass.rb:14:5:14:9 | call to login | action | ConditionalBypass.rb:14:14:14:19 | call to params | a user-provided value |
| ConditionalBypass.rb:27:8:27:8 | p | ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:27:8:27:8 | p | This condition guards a sensitive $@, but $@ controls it. | ConditionalBypass.rb:28:7:28:13 | call to verify! | action | ConditionalBypass.rb:25:10:25:15 | call to params | a user-provided value |

View File

@@ -0,0 +1 @@
experimental/cwe-807/ConditionalBypass.ql

View File

@@ -0,0 +1,39 @@
class FooController < ActionController::Base
def bad_handler1
check = params[:check]
name = params[:name]
if check
# BAD
authenticate_user! name
end
end
def bad_handler2
# BAD
login if params[:login]
do_something_else
end
def bad_handler3
# BAD. Not detected: its the last statement in the method, so it doesn't
# match the heuristic for an action.
login if params[:login]
end
def bad_handler4
p = (params[:name] == "foo")
# BAD
if p
verify!
end
end
def good_handler
name = params[:name]
# Call to a sensitive action, but the guard is not derived from user input.
if should_auth_user?
authenticate_user! name
end
end
end