Merge pull request #19206 from hvitved/ruby/super-implicit-args-synth

Ruby: Synthesize implicit super arguments
This commit is contained in:
yoff
2025-04-07 11:57:12 +02:00
committed by GitHub
21 changed files with 1598 additions and 308 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Calls to `super` without explict arguments now have their implicit arguments generated. For example, in `def foo(x, y) { super } end` the call to `super` becomes `super(x, y)`.

View File

@@ -248,13 +248,7 @@ class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr {
* baz(qux: 1)
* ```
*/
class Pair extends Expr, TPair {
private Ruby::Pair g;
Pair() { this = TPair(g) }
final override string getAPrimaryQlClass() { result = "Pair" }
class Pair extends Expr instanceof PairImpl {
/**
* Gets the key expression of this pair. For example, the `SymbolLiteral`
* representing the keyword `foo` in the following example:
@@ -266,7 +260,7 @@ class Pair extends Expr, TPair {
* { 'foo' => 123 }
* ```
*/
final Expr getKey() { toGenerated(result) = g.getKey() }
final Expr getKey() { result = PairImpl.super.getKey() }
/**
* Gets the value expression of this pair. For example, the `IntegerLiteral`
@@ -275,20 +269,9 @@ class Pair extends Expr, TPair {
* { 'foo' => 123 }
* ```
*/
final Expr getValue() {
toGenerated(result) = g.getValue() or
synthChild(this, 0, result)
}
final Expr getValue() { result = PairImpl.super.getValue() }
final override string toString() { result = "Pair" }
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getKey" and result = this.getKey()
or
pred = "getValue" and result = this.getValue()
}
final override string getAPrimaryQlClass() { result = "Pair" }
}
/**

View File

@@ -305,7 +305,9 @@ class StringlikeLiteral extends Literal instanceof StringlikeLiteralImpl {
final override AstNode getAChild(string pred) {
result = Literal.super.getAChild(pred)
or
pred = "getComponent" and result = this.getComponent(_)
pred = "getComponent" and
result = this.getComponent(_) and
not this instanceof SimpleSymbolLiteralSynth
}
}

View File

@@ -92,10 +92,6 @@ class SplatExpr extends UnaryOperation, TSplatExpr {
* ```
*/
class HashSplatExpr extends UnaryOperation, THashSplatExpr {
private Ruby::HashSplatArgument g;
HashSplatExpr() { this = THashSplatExpr(g) }
final override string getAPrimaryQlClass() { result = "HashSplatExpr" }
}

View File

@@ -164,7 +164,8 @@ private module Cached {
THashKeySymbolLiteral(Ruby::HashKeySymbol g) or
THashLiteral(Ruby::Hash g) or
THashPattern(Ruby::HashPattern g) or
THashSplatExpr(Ruby::HashSplatArgument g) or
THashSplatExprReal(Ruby::HashSplatArgument g) or
THashSplatExprSynth(Ast::AstNode parent, int i) { mkSynthChild(HashSplatExprKind(), parent, i) } or
THashSplatNilParameter(Ruby::HashSplatNil g) { not g.getParent() instanceof Ruby::HashPattern } or
THashSplatParameter(Ruby::HashSplatParameter g) {
not g.getParent() instanceof Ruby::HashPattern
@@ -232,7 +233,8 @@ private module Cached {
TNotExprReal(Ruby::Unary g) { g instanceof @ruby_unary_bang or g instanceof @ruby_unary_not } or
TNotExprSynth(Ast::AstNode parent, int i) { mkSynthChild(NotExprKind(), parent, i) } or
TOptionalParameter(Ruby::OptionalParameter g) or
TPair(Ruby::Pair g) or
TPairReal(Ruby::Pair g) or
TPairSynth(Ast::AstNode parent, int i) { mkSynthChild(PairExprKind(), parent, i) } or
TParenthesizedExpr(Ruby::ParenthesizedStatements g) or
TParenthesizedPattern(Ruby::ParenthesizedPattern g) or
TRShiftExprReal(Ruby::Binary g) { g instanceof @ruby_binary_ranglerangle } or
@@ -274,7 +276,10 @@ private module Cached {
TSimpleParameterSynth(Ast::AstNode parent, int i) {
mkSynthChild(SimpleParameterKind(), parent, i)
} or
TSimpleSymbolLiteral(Ruby::SimpleSymbol g) or
TSimpleSymbolLiteralReal(Ruby::SimpleSymbol g) or
TSimpleSymbolLiteralSynth(Ast::AstNode parent, int i, string value) {
mkSynthChild(SymbolLiteralExprKind(value), parent, i)
} or
TSingletonClass(Ruby::SingletonClass g) or
TSingletonMethod(Ruby::SingletonMethod g) or
TSpaceshipExpr(Ruby::Binary g) { g instanceof @ruby_binary_langleequalrangle } or
@@ -362,19 +367,19 @@ private module Cached {
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
THashSplatExprReal or THashSplatNilParameter or THashSplatParameter or THereDoc or
TIdentifierMethodCall or TIfReal or TIfModifierExpr or TInClauseReal or
TInstanceVariableAccessReal or TIntegerLiteralReal or TKeywordParameter or TLEExpr or
TLShiftExprReal or TLTExpr or TLambda or TLeftAssignmentList or TLine or
TLocalVariableAccessReal or TLogicalAndExprReal or TLogicalOrExprReal or TMethod or
TMatchPattern or TModuleDeclaration or TModuloExprReal or TMulExprReal or TNEExpr or
TNextStmt or TNilLiteralReal or TNoRegExpMatchExpr or TNotExprReal or TOptionalParameter or
TPair or TParenthesizedExpr or TParenthesizedPattern or TRShiftExprReal or
TPairReal or TParenthesizedExpr or TParenthesizedPattern or TRShiftExprReal or
TRangeLiteralReal or TRationalLiteral or TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or
TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or
TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or
TScopeResolutionConstantAccess or TSelfReal or TSimpleParameterReal or
TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or TSpaceshipExpr or
TSimpleSymbolLiteralReal or TSingletonClass or TSingletonMethod or TSpaceshipExpr or
TSplatExprReal or TSplatParameter or TStringArrayLiteral or TStringConcatenation or
TStringEscapeSequenceComponent or TStringInterpolationComponent or TStringTextComponent or
TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or TTernaryIfExpr or TTestPattern or
@@ -392,7 +397,8 @@ private module Cached {
TLShiftExprSynth or TLocalVariableAccessSynth or TLogicalAndExprSynth or
TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or TMulExprSynth or
TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or
TSimpleParameterSynth or TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth;
TSimpleParameterSynth or TSplatExprSynth or THashSplatExprSynth or TStmtSequenceSynth or
TSubExprSynth or TPairSynth or TSimpleSymbolLiteralSynth;
/**
* Gets the underlying TreeSitter entity for a given AST node. This does not
@@ -468,7 +474,7 @@ private module Cached {
n = THashKeySymbolLiteral(result) or
n = THashLiteral(result) or
n = THashPattern(result) or
n = THashSplatExpr(result) or
n = THashSplatExprReal(result) or
n = THashSplatNilParameter(result) or
n = THashSplatParameter(result) or
n = THereDoc(result) or
@@ -499,7 +505,7 @@ private module Cached {
n = TNoRegExpMatchExpr(result) or
n = TNotExprReal(result) or
n = TOptionalParameter(result) or
n = TPair(result) or
n = TPairReal(result) or
n = TParenthesizedExpr(result) or
n = TParenthesizedPattern(result) or
n = TRangeLiteralReal(result) or
@@ -519,7 +525,7 @@ private module Cached {
n = TScopeResolutionConstantAccess(result, _) or
n = TSelfReal(result) or
n = TSimpleParameterReal(result) or
n = TSimpleSymbolLiteral(result) or
n = TSimpleSymbolLiteralReal(result) or
n = TSingletonClass(result) or
n = TSingletonMethod(result) or
n = TSpaceshipExpr(result) or
@@ -633,9 +639,15 @@ private module Cached {
or
result = TSplatExprSynth(parent, i)
or
result = THashSplatExprSynth(parent, i)
or
result = TStmtSequenceSynth(parent, i)
or
result = TSubExprSynth(parent, i)
or
result = TPairSynth(parent, i)
or
result = TSimpleSymbolLiteralSynth(parent, i, _)
}
/**
@@ -726,6 +738,8 @@ class TSelf = TSelfReal or TSelfSynth;
class TDestructuredLhsExpr = TDestructuredLeftAssignment or TLeftAssignmentList;
class TPair = TPairReal or TPairSynth;
class TExpr =
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
TCall or TBlockArgument or TConstantAccess or TControlExpr or TLiteral or TCallable or
@@ -734,6 +748,8 @@ class TExpr =
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
class THashSplatExpr = THashSplatExprReal or THashSplatExprSynth;
class TElse = TElseReal or TElseSynth;
class TStmtSequence =
@@ -768,13 +784,16 @@ class TStringInterpolationComponent =
TStringInterpolationComponentNonRegexp or TStringInterpolationComponentRegexp;
class TStringComponent =
TStringTextComponent or TStringEscapeSequenceComponent or TStringInterpolationComponent;
TStringTextComponent or TStringEscapeSequenceComponent or TStringInterpolationComponent or
TSimpleSymbolLiteralSynth;
class TStringlikeLiteral =
TStringLiteral or TRegExpLiteral or TSymbolLiteral or TSubshellLiteral or THereDoc;
class TStringLiteral = TRegularStringLiteral or TBareStringLiteral;
class TSimpleSymbolLiteral = TSimpleSymbolLiteralReal or TSimpleSymbolLiteralSynth;
class TSymbolLiteral = TSimpleSymbolLiteral or TComplexSymbolLiteral or THashKeySymbolLiteral;
class TComplexSymbolLiteral = TDelimitedSymbolLiteral or TBareSymbolLiteral;

View File

@@ -2,6 +2,7 @@ private import TreeSitter
private import Variable
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST
private import codeql.ruby.ast.internal.Scope
predicate isIdentifierMethodCall(Ruby::Identifier g) { vcall(g) and not access(g, _) }
@@ -133,18 +134,61 @@ private string getSuperMethodName(Ruby::Super sup) {
)
}
private Ruby::Identifier getParameter(Ruby::Method m, int pos, Ruby::AstNode param) {
scopeDefinesParameterVariable(m, _, result, pos) and
param = m.getParameters().getChild(pos)
}
class TokenSuperCall extends SuperCallImpl, TTokenSuperCall {
private Ruby::Super g;
TokenSuperCall() { this = TTokenSuperCall(g) }
Ruby::Method getEnclosingMethod() { result = scopeOf(toGenerated(this)).getEnclosingMethod() }
int getNumberOfImplicitArguments() {
exists(Ruby::Method encl |
encl = this.getEnclosingMethod() and
result = count(getParameter(encl, _, _))
)
}
/**
* Gets the local variable defined by parameter `param` which is used as an
* implicit argument at position `pos`.
*
* For example, in
*
* ```ruby
* class Sup
* def m(x)
* end
* end
*
* class Sub < Sup
* def m(x)
* super
* end
* end
* ```
*
* `x` is an implicit argument at position 0 of the `super` call in `Sub#m`.
*/
pragma[nomagic]
LocalVariableReal getImplicitArgument(int pos, Ruby::AstNode param) {
exists(Ruby::Method encl |
encl = this.getEnclosingMethod() and
toGenerated(result.getDefiningAccessImpl()) = getParameter(encl, pos, param)
)
}
final override string getMethodNameImpl() { result = getSuperMethodName(g) }
final override Expr getReceiverImpl() { none() }
final override Expr getArgumentImpl(int n) { none() }
final override Expr getArgumentImpl(int n) { synthChild(this, n, result) }
final override int getNumberOfArgumentsImpl() { result = 0 }
final override int getNumberOfArgumentsImpl() { result = this.getNumberOfImplicitArguments() }
final override Block getBlockImpl() { none() }
}

View File

@@ -120,3 +120,38 @@ class LeftAssignmentListImpl extends DestructuredLhsExprImpl, Ruby::LeftAssignme
)
}
}
abstract class PairImpl extends Expr, TPair {
abstract Expr getKey();
abstract Expr getValue();
final override string toString() { result = "Pair" }
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getKey" and result = this.getKey()
or
pred = "getValue" and result = this.getValue()
}
}
class PairReal extends PairImpl, TPairReal {
private Ruby::Pair g;
PairReal() { this = TPairReal(g) }
final override Expr getKey() { toGenerated(result) = g.getKey() }
final override Expr getValue() {
toGenerated(result) = g.getValue() or
synthChild(this, 0, result)
}
}
class PairSynth extends PairImpl, TPairSynth {
final override Expr getKey() { synthChild(this, 0, result) }
final override Expr getValue() { synthChild(this, 1, result) }
}

View File

@@ -608,16 +608,32 @@ class BareStringLiteral extends StringLiteralImpl, TBareStringLiteral {
abstract class SymbolLiteralImpl extends StringlikeLiteralImpl, TSymbolLiteral { }
class SimpleSymbolLiteral extends SymbolLiteralImpl, TSimpleSymbolLiteral {
abstract class SimpleSymbolLiteralImpl extends SymbolLiteralImpl, TSimpleSymbolLiteral { }
class SimpleSymbolLiteralReal extends SimpleSymbolLiteralImpl, TSimpleSymbolLiteral {
private Ruby::SimpleSymbol g;
SimpleSymbolLiteral() { this = TSimpleSymbolLiteral(g) }
SimpleSymbolLiteralReal() { this = TSimpleSymbolLiteralReal(g) }
final override StringComponent getComponentImpl(int n) { n = 0 and toGenerated(result) = g }
final override string toString() { result = g.getValue() }
}
class SimpleSymbolLiteralSynth extends SimpleSymbolLiteralImpl, TSimpleSymbolLiteralSynth,
StringComponentImpl
{
private string value;
SimpleSymbolLiteralSynth() { this = TSimpleSymbolLiteralSynth(_, _, value) }
final override string getValue() { result = value }
final override StringComponent getComponentImpl(int n) { n = 0 and result = this }
final override string toString() { result = value }
}
abstract class ComplexSymbolLiteral extends SymbolLiteralImpl, TComplexSymbolLiteral { }
class DelimitedSymbolLiteral extends ComplexSymbolLiteral, TDelimitedSymbolLiteral {

View File

@@ -45,36 +45,42 @@ class NotExprSynth extends NotExprImpl, TNotExprSynth {
final override Expr getOperandImpl() { synthChild(this, 0, result) }
}
class SplatExprReal extends UnaryOperationImpl, TSplatExprReal {
abstract class SplatExprImpl extends UnaryOperationImpl, TSplatExpr {
final override string getOperatorImpl() { result = "*" }
}
class SplatExprReal extends SplatExprImpl, TSplatExprReal {
private Ruby::SplatArgument g;
SplatExprReal() { this = TSplatExprReal(g) }
final override string getOperatorImpl() { result = "*" }
final override Expr getOperandImpl() {
toGenerated(result) = g.getChild() or
synthChild(this, 0, result)
}
}
class SplatExprSynth extends UnaryOperationImpl, TSplatExprSynth {
final override string getOperatorImpl() { result = "*" }
class SplatExprSynth extends SplatExprImpl, TSplatExprSynth {
final override Expr getOperandImpl() { synthChild(this, 0, result) }
}
class HashSplatExprImpl extends UnaryOperationImpl, THashSplatExpr {
abstract class HashSplatExprImpl extends UnaryOperationImpl, THashSplatExpr {
final override string getOperatorImpl() { result = "**" }
}
class HashSplatExprReal extends HashSplatExprImpl, THashSplatExprReal {
private Ruby::HashSplatArgument g;
HashSplatExprImpl() { this = THashSplatExpr(g) }
HashSplatExprReal() { this = THashSplatExprReal(g) }
final override Expr getOperandImpl() {
toGenerated(result) = g.getChild() or
synthChild(this, 0, result)
}
}
final override string getOperatorImpl() { result = "**" }
class HashSplatExprSynth extends HashSplatExprImpl, THashSplatExprSynth {
final override Expr getOperandImpl() { synthChild(this, 0, result) }
}
abstract class DefinedExprImpl extends UnaryOperationImpl, TDefinedExpr { }

View File

@@ -11,7 +11,7 @@ private import codeql.ruby.ast.internal.Scope
private import codeql.ruby.AST
/** A synthesized AST node kind. */
newtype SynthKind =
newtype TSynthKind =
AddExprKind() or
AssignExprKind() or
BitwiseAndExprKind() or
@@ -42,16 +42,107 @@ newtype SynthKind =
MulExprKind() or
NilLiteralKind() or
NotExprKind() or
PairExprKind() or
RangeLiteralKind(boolean inclusive) { inclusive in [false, true] } or
RShiftExprKind() or
SimpleParameterKind() or
SplatExprKind() or
HashSplatExprKind() or
SymbolLiteralExprKind(string value) {
value = any(Ruby::SimpleSymbol s).getValue()
or
value = any(Ruby::KeywordParameter p).getName().getValue()
} or
StmtSequenceKind() or
SelfKind(SelfVariable v) or
SubExprKind() or
ConstantReadAccessKind(string value) { any(Synthesis s).constantReadAccess(value) } or
ConstantWriteAccessKind(string value) { any(Synthesis s).constantWriteAccess(value) }
class SynthKind extends TSynthKind {
string toString() {
this = AddExprKind() and result = "AddExprKind"
or
this = AssignExprKind() and result = "AssignExprKind"
or
this = BitwiseAndExprKind() and result = "BitwiseAndExprKind"
or
this = BitwiseOrExprKind() and result = "BitwiseOrExprKind"
or
this = BitwiseXorExprKind() and result = "BitwiseXorExprKind"
or
this = BooleanLiteralKind(_) and result = "BooleanLiteralKind"
or
this = BraceBlockKind() and result = "BraceBlockKind"
or
this = CaseMatchKind() and result = "CaseMatchKind"
or
this = ClassVariableAccessKind(_) and result = "ClassVariableAccessKind"
or
this = DefinedExprKind() and result = "DefinedExprKind"
or
this = DivExprKind() and result = "DivExprKind"
or
this = ElseKind() and result = "ElseKind"
or
this = ExponentExprKind() and result = "ExponentExprKind"
or
this = GlobalVariableAccessKind(_) and result = "GlobalVariableAccessKind"
or
this = IfKind() and result = "IfKind"
or
this = InClauseKind() and result = "InClauseKind"
or
this = InstanceVariableAccessKind(_) and result = "InstanceVariableAccessKind"
or
this = IntegerLiteralKind(_) and result = "IntegerLiteralKind"
or
this = LShiftExprKind() and result = "LShiftExprKind"
or
this = LocalVariableAccessRealKind(_) and result = "LocalVariableAccessRealKind"
or
this = LocalVariableAccessSynthKind(_) and result = "LocalVariableAccessSynthKind"
or
this = LogicalAndExprKind() and result = "LogicalAndExprKind"
or
this = LogicalOrExprKind() and result = "LogicalOrExprKind"
or
this = MethodCallKind(_, _, _) and result = "MethodCallKind"
or
this = ModuloExprKind() and result = "ModuloExprKind"
or
this = MulExprKind() and result = "MulExprKind"
or
this = NilLiteralKind() and result = "NilLiteralKind"
or
this = NotExprKind() and result = "NotExprKind"
or
this = PairExprKind() and result = "PairExprKind"
or
this = RangeLiteralKind(_) and result = "RangeLiteralKind"
or
this = RShiftExprKind() and result = "RShiftExprKind"
or
this = SimpleParameterKind() and result = "SimpleParameterKind"
or
this = SplatExprKind() and result = "SplatExprKind"
or
this = HashSplatExprKind() and result = "HashSplatExprKind"
or
this = SymbolLiteralExprKind(_) and result = "SymbolLiteralExprKind"
or
this = StmtSequenceKind() and result = "StmtSequenceKind"
or
this = SubExprKind() and result = "SubExprKind"
or
this = SelfKind(_) and result = "SelfKind"
or
this = ConstantReadAccessKind(_) and result = "ConstantReadAccessKind"
or
this = ConstantWriteAccessKind(_) and result = "ConstantWriteAccessKind"
}
}
/**
* An AST child.
*
@@ -441,7 +532,7 @@ private module AssignOperationDesugar {
pragma[nomagic]
SynthKind getVariableAccessKind() {
result in [
LocalVariableAccessRealKind(v).(SynthKind), InstanceVariableAccessKind(v),
LocalVariableAccessRealKind(v).(TSynthKind), InstanceVariableAccessKind(v),
ClassVariableAccessKind(v), GlobalVariableAccessKind(v)
]
}
@@ -1802,3 +1893,59 @@ private module MatchPatternDesugar {
}
}
}
private module ImplicitSuperArgsSynthesis {
pragma[nomagic]
private predicate superCallSynthesis(AstNode parent, int i, Child child) {
exists(TokenSuperCall call, SynthChild access, int pos, Ruby::AstNode param |
access = SynthChild(LocalVariableAccessRealKind(call.getImplicitArgument(pos, param)))
|
parent = call and
param instanceof Ruby::Identifier and
i = pos and
child = access
or
param instanceof Ruby::SplatParameter and
(
parent = call and
i = pos and
child = SynthChild(SplatExprKind())
or
parent = TSplatExprSynth(call, pos) and
i = 0 and
child = access
)
or
param instanceof Ruby::HashSplatParameter and
(
parent = call and
i = pos and
child = SynthChild(HashSplatExprKind())
or
parent = THashSplatExprSynth(call, pos) and
i = 0 and
child = access
)
or
exists(string name | name = param.(Ruby::KeywordParameter).getName().getValue() |
parent = call and
i = pos and
child = SynthChild(PairExprKind())
or
parent = TPairSynth(call, pos) and
i = 0 and
child = SynthChild(SymbolLiteralExprKind(name))
or
parent = TPairSynth(call, pos) and
i = 1 and
child = access
)
)
}
private class SuperCallSynthesis extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
superCallSynthesis(parent, i, child)
}
}
}

View File

@@ -49,11 +49,11 @@ predicate implicitAssignmentNode(Ruby::AstNode n) {
}
/** Holds if `n` is inside a parameter. */
predicate implicitParameterAssignmentNode(Ruby::AstNode n, Callable::Range c) {
n = c.getParameter(_) or
n = c.(Ruby::Block).getParameters().getLocals(_) or
n = c.(Ruby::DoBlock).getParameters().getLocals(_) or
implicitParameterAssignmentNode(n.getParent().(Ruby::DestructuredParameter), c)
predicate implicitParameterAssignmentNode(Ruby::AstNode n, Callable::Range c, int pos) {
n = c.getParameter(pos) or
n = c.(Ruby::Block).getParameters().getLocals(pos) or
n = c.(Ruby::DoBlock).getParameters().getLocals(pos) or
implicitParameterAssignmentNode(n.getParent().(Ruby::DestructuredParameter), c, pos)
}
private predicate instanceVariableAccess(
@@ -77,26 +77,29 @@ private ModuleBase::Range enclosingModuleOrClass(Ruby::AstNode node) {
exists(Scope::Range s | scopeOf(node) = s and result = s.getEnclosingModule())
}
private predicate parameterAssignment(Callable::Range scope, string name, Ruby::Identifier i) {
implicitParameterAssignmentNode(i, scope) and
private predicate parameterAssignment(
Callable::Range scope, string name, Ruby::Identifier i, int pos
) {
implicitParameterAssignmentNode(i, scope, pos) and
name = i.getValue()
}
/** Holds if `scope` defines `name` in its parameter declaration at `i`. */
private predicate scopeDefinesParameterVariable(
Callable::Range scope, string name, Ruby::Identifier i
predicate scopeDefinesParameterVariable(
Callable::Range scope, string name, Ruby::Identifier i, int pos
) {
// In case of overlapping parameter names (e.g. `_`), only the first
// parameter will give rise to a variable
i =
min(Ruby::Identifier other |
parameterAssignment(scope, name, other)
parameterAssignment(scope, name, other, _)
|
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
)
) and
parameterAssignment(scope, name, _, pos)
or
exists(Parameter::Range p |
p = scope.getParameter(_) and
p = scope.getParameter(pos) and
name = i.getValue()
|
i = p.(Ruby::BlockParameter).getName() or
@@ -153,7 +156,7 @@ private module Cached {
)
} or
TLocalVariableReal(Scope::Range scope, string name, Ruby::AstNode i) {
scopeDefinesParameterVariable(scope, name, i)
scopeDefinesParameterVariable(scope, name, i, _)
or
i =
min(Ruby::AstNode other |
@@ -161,7 +164,7 @@ private module Cached {
|
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
) and
not scopeDefinesParameterVariable(scope, name, _) and
not scopeDefinesParameterVariable(scope, name, _, _) and
not inherits(scope, name, _)
} or
TSelfVariable(SelfBase::Range scope) or
@@ -330,8 +333,8 @@ private module Cached {
not access.getLocation().strictlyBefore(variable.getLocationImpl()) and
// In case of overlapping parameter names, later parameters should not
// be considered accesses to the first parameter
if parameterAssignment(_, _, access)
then scopeDefinesParameterVariable(_, _, access)
if parameterAssignment(_, _, access, _)
then scopeDefinesParameterVariable(_, _, access, _)
else any()
or
exists(Scope::Range declScope |
@@ -360,7 +363,7 @@ private module Cached {
predicate implicitWriteAccess(Access access) {
implicitAssignmentNode(access)
or
scopeDefinesParameterVariable(_, _, access)
scopeDefinesParameterVariable(_, _, access, _)
}
cached
@@ -399,11 +402,11 @@ private predicate inherits(Scope::Range scope, string name, Scope::Range outer)
scope instanceof Ruby::DoBlock or
scope instanceof Ruby::Lambda
) and
not scopeDefinesParameterVariable(scope, name, _) and
not scopeDefinesParameterVariable(scope, name, _, _) and
(
outer = scope.getOuterScope() and
(
scopeDefinesParameterVariable(outer, name, _)
scopeDefinesParameterVariable(outer, name, _, _)
or
exists(Ruby::AstNode i |
scopeAssigns(outer, name, i) and

View File

@@ -1430,7 +1430,10 @@ module Trees {
}
private class StringlikeLiteralTree extends StandardPostOrderTree instanceof StringlikeLiteral {
StringlikeLiteralTree() { not this instanceof HereDoc }
StringlikeLiteralTree() {
not this instanceof HereDoc and
not this instanceof AstInternal::TSimpleSymbolLiteralSynth
}
final override ControlFlowTree getChildNode(int i) { result = super.getComponent(i) }
}

View File

@@ -1,6 +1,7 @@
private import codeql.util.Boolean
private import codeql.util.Unit
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.Call
private import codeql.ruby.ast.internal.Synthesis
private import codeql.ruby.CFG
private import codeql.ruby.dataflow.SSA
@@ -483,9 +484,12 @@ private module Cached {
TSelfToplevelParameterNode(Toplevel t) or
TLambdaSelfReferenceNode(Callable c) { lambdaCreationExpr(_, _, c) } or
TImplicitBlockParameterNode(MethodBase m) { not m.getAParameter() instanceof BlockParameter } or
TImplicitBlockArgumentNode(CfgNodes::ExprNodes::CallCfgNode yield) {
TImplicitYieldBlockArgumentNode(CfgNodes::ExprNodes::CallCfgNode yield) {
yield = any(BlockParameterNode b).getAYieldCall()
} or
TImplicitSuperBlockArgumentNode(CfgNodes::ExprNodes::CallCfgNode sup) {
sup = any(BlockParameterNode b).getASuperCall()
} or
TSynthHashSplatParameterNode(DataFlowCallable c) {
isParameterNode(_, c, any(ParameterPosition p | p.isKeyword(_)))
} or
@@ -1049,6 +1053,11 @@ private module ParameterNodes {
CfgNodes::ExprNodes::CallCfgNode getAYieldCall() {
this.getMethod() = result.getExpr().(YieldCall).getEnclosingMethod()
}
CfgNodes::ExprNodes::CallCfgNode getASuperCall() {
this.getMethod() = result.getExpr().getEnclosingMethod() and
result.getExpr() instanceof TokenSuperCall
}
}
private class ExplicitBlockParameterNode extends BlockParameterNode, NormalParameterNode {
@@ -1315,15 +1324,23 @@ module ArgumentNodes {
}
}
class ImplicitBlockArgumentNode extends NodeImpl, ArgumentNode, TImplicitBlockArgumentNode {
abstract class ImplicitBlockArgumentNode extends NodeImpl, ArgumentNode {
pragma[nomagic]
abstract BlockParameterNode getParameterNode(boolean inSameScope);
override string toStringImpl() { result = "yield block argument" }
}
class ImplicitYieldBlockArgumentNode extends ImplicitBlockArgumentNode,
TImplicitYieldBlockArgumentNode
{
CfgNodes::ExprNodes::CallCfgNode yield;
ImplicitBlockArgumentNode() { this = TImplicitBlockArgumentNode(yield) }
ImplicitYieldBlockArgumentNode() { this = TImplicitYieldBlockArgumentNode(yield) }
CfgNodes::ExprNodes::CallCfgNode getYieldCall() { result = yield }
pragma[nomagic]
BlockParameterNode getParameterNode(boolean inSameScope) {
override BlockParameterNode getParameterNode(boolean inSameScope) {
result.getAYieldCall() = yield and
if nodeGetEnclosingCallable(this) = nodeGetEnclosingCallable(result)
then inSameScope = true
@@ -1343,8 +1360,36 @@ module ArgumentNodes {
override CfgScope getCfgScope() { result = yield.getScope() }
override Location getLocationImpl() { result = yield.getLocation() }
}
override string toStringImpl() { result = "yield block argument" }
class ImplicitSuperBlockArgumentNode extends ImplicitBlockArgumentNode,
TImplicitSuperBlockArgumentNode
{
CfgNodes::ExprNodes::CallCfgNode sup;
ImplicitSuperBlockArgumentNode() { this = TImplicitSuperBlockArgumentNode(sup) }
CfgNodes::ExprNodes::CallCfgNode getSuperCall() { result = sup }
override BlockParameterNode getParameterNode(boolean inSameScope) {
result.getASuperCall() = sup and
if nodeGetEnclosingCallable(this) = nodeGetEnclosingCallable(result)
then inSameScope = true
else inSameScope = false
}
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
call = sup and
pos.isBlock()
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
this.sourceArgumentOf(call.asCall(), pos)
}
override CfgScope getCfgScope() { result = sup.getScope() }
override Location getLocationImpl() { result = sup.getLocation() }
}
private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
@@ -2158,7 +2203,7 @@ private predicate lambdaCallExpr(
*/
predicate lambdaSourceCall(CfgNodes::ExprNodes::CallCfgNode call, LambdaCallKind kind, Node receiver) {
kind = TYieldCallKind() and
call = receiver.(ImplicitBlockArgumentNode).getYieldCall()
call = receiver.(ImplicitYieldBlockArgumentNode).getYieldCall()
or
kind = TLambdaCallKind() and
lambdaCallExpr(call, receiver.asExpr())

View File

@@ -3153,6 +3153,54 @@ params/params.rb:
# 95| getReceiver: [LocalVariableAccess] hash
# 95| getArgument: [HashSplatExpr] ** ...
# 95| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0
# 98| getStmt: [ClassDeclaration] Sup
# 99| getStmt: [Method] m
# 99| getParameter: [SimpleParameter] x
# 99| getDefiningAccess: [LocalVariableAccess] x
# 99| getParameter: [SplatParameter] *rest
# 99| getDefiningAccess: [LocalVariableAccess] rest
# 99| getParameter: [KeywordParameter] k
# 99| getDefiningAccess: [LocalVariableAccess] k
# 99| getParameter: [HashSplatParameter] **kwargs
# 99| getDefiningAccess: [LocalVariableAccess] kwargs
# 100| getStmt: [MethodCall] call to print
# 100| getReceiver: [SelfVariableAccess] self
# 100| getArgument: [AddExpr] ... + ...
# 100| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x
# 100| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
# 101| getStmt: [MethodCall] call to print
# 101| getReceiver: [SelfVariableAccess] self
# 101| getArgument: [AddExpr] ... + ...
# 101| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] k
# 101| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
# 105| getStmt: [ClassDeclaration] Sub
# 105| getSuperclassExpr: [ConstantReadAccess] Sup
# 106| getStmt: [Method] m
# 106| getParameter: [SimpleParameter] y
# 106| getDefiningAccess: [LocalVariableAccess] y
# 106| getParameter: [SplatParameter] *rest
# 106| getDefiningAccess: [LocalVariableAccess] rest
# 106| getParameter: [KeywordParameter] k
# 106| getDefiningAccess: [LocalVariableAccess] k
# 106| getParameter: [HashSplatParameter] **kwargs
# 106| getDefiningAccess: [LocalVariableAccess] kwargs
# 107| getStmt: [SuperCall] super call to m
# 107| getArgument: [HashSplatExpr] ** ...
# 107| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] kwargs
# 107| getArgument: [Pair] Pair
# 107| getKey: [SymbolLiteral] k
# 107| getValue: [LocalVariableAccess] k
# 107| getArgument: [SplatExpr] * ...
# 107| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] rest
# 107| getArgument: [LocalVariableAccess] y
# 111| getStmt: [MethodCall] call to m
# 111| getReceiver: [MethodCall] call to new
# 111| getReceiver: [ConstantReadAccess] Sub
# 111| getArgument: [IntegerLiteral] 42
# 111| getArgument: [Pair] Pair
# 111| getKey: [SymbolLiteral] :k
# 111| getComponent: [StringTextComponent] k
# 111| getValue: [IntegerLiteral] 22
erb/template.html.erb:
# 19| [Toplevel] template.html.erb
# 19| getStmt: [StringLiteral] "hello world"

View File

@@ -6192,6 +6192,96 @@ params/params.rb:
# 95| 0: [ReservedWord] **
# 95| 2: [ReservedWord] )
# 96| 4: [ReservedWord] end
# 98| 25: [Class] Class
# 98| 0: [ReservedWord] class
# 98| 1: [Constant] Sup
# 99| 2: [BodyStatement] BodyStatement
# 99| 0: [Method] Method
# 99| 0: [ReservedWord] def
# 99| 1: [Identifier] m
# 99| 2: [MethodParameters] MethodParameters
# 99| 0: [ReservedWord] (
# 99| 1: [Identifier] x
# 99| 2: [ReservedWord] ,
# 99| 3: [SplatParameter] SplatParameter
# 99| 0: [ReservedWord] *
# 99| 1: [Identifier] rest
# 99| 4: [ReservedWord] ,
# 99| 5: [KeywordParameter] KeywordParameter
# 99| 0: [Identifier] k
# 99| 1: [ReservedWord] :
# 99| 6: [ReservedWord] ,
# 99| 7: [HashSplatParameter] HashSplatParameter
# 99| 0: [ReservedWord] **
# 99| 1: [Identifier] kwargs
# 99| 8: [ReservedWord] )
# 100| 3: [BodyStatement] BodyStatement
# 100| 0: [Call] Call
# 100| 0: [Identifier] print
# 100| 1: [ArgumentList] ArgumentList
# 100| 0: [ReservedWord] (
# 100| 1: [Binary] Binary
# 100| 0: [Identifier] x
# 100| 1: [ReservedWord] +
# 100| 2: [Integer] 1
# 100| 2: [ReservedWord] )
# 101| 1: [Call] Call
# 101| 0: [Identifier] print
# 101| 1: [ArgumentList] ArgumentList
# 101| 0: [ReservedWord] (
# 101| 1: [Binary] Binary
# 101| 0: [Identifier] k
# 101| 1: [ReservedWord] +
# 101| 2: [Integer] 1
# 101| 2: [ReservedWord] )
# 102| 4: [ReservedWord] end
# 103| 3: [ReservedWord] end
# 105| 26: [Class] Class
# 105| 0: [ReservedWord] class
# 105| 1: [Constant] Sub
# 105| 2: [Superclass] Superclass
# 105| 0: [ReservedWord] <
# 105| 1: [Constant] Sup
# 106| 3: [BodyStatement] BodyStatement
# 106| 0: [Method] Method
# 106| 0: [ReservedWord] def
# 106| 1: [Identifier] m
# 106| 2: [MethodParameters] MethodParameters
# 106| 0: [ReservedWord] (
# 106| 1: [Identifier] y
# 106| 2: [ReservedWord] ,
# 106| 3: [SplatParameter] SplatParameter
# 106| 0: [ReservedWord] *
# 106| 1: [Identifier] rest
# 106| 4: [ReservedWord] ,
# 106| 5: [KeywordParameter] KeywordParameter
# 106| 0: [Identifier] k
# 106| 1: [ReservedWord] :
# 106| 6: [ReservedWord] ,
# 106| 7: [HashSplatParameter] HashSplatParameter
# 106| 0: [ReservedWord] **
# 106| 1: [Identifier] kwargs
# 106| 8: [ReservedWord] )
# 107| 3: [BodyStatement] BodyStatement
# 107| 0: [Super] super
# 108| 4: [ReservedWord] end
# 109| 4: [ReservedWord] end
# 111| 27: [Call] Call
# 111| 0: [Call] Call
# 111| 0: [Constant] Sub
# 111| 1: [ReservedWord] .
# 111| 2: [Identifier] new
# 111| 1: [ReservedWord] .
# 111| 2: [Identifier] m
# 111| 3: [ArgumentList] ArgumentList
# 111| 0: [ReservedWord] (
# 111| 1: [Integer] 42
# 111| 2: [ReservedWord] ,
# 111| 3: [Pair] Pair
# 111| 0: [HashKeySymbol] k
# 111| 1: [ReservedWord] :
# 111| 2: [Integer] 22
# 111| 4: [ReservedWord] )
# 1| [Comment] # Tests for the different kinds and contexts of parameters.
# 3| [Comment] # Method containing identifier parameters
# 7| [Comment] # Block containing identifier parameters

View File

@@ -941,6 +941,12 @@ exprValue
| params/params.rb:65:41:65:42 | 99 | 99 | int |
| params/params.rb:70:42:70:45 | 1000 | 1000 | int |
| params/params.rb:70:52:70:53 | 20 | 20 | int |
| params/params.rb:100:15:100:15 | 1 | 1 | int |
| params/params.rb:101:15:101:15 | 1 | 1 | int |
| params/params.rb:107:5:107:9 | k | :k | symbol |
| params/params.rb:111:11:111:12 | 42 | 42 | int |
| params/params.rb:111:15:111:15 | :k | :k | symbol |
| params/params.rb:111:18:111:19 | 22 | 22 | int |
exprCfgNodeValue
| calls/calls.rb:8:1:8:3 | 123 | 123 | int |
| calls/calls.rb:11:5:11:5 | 0 | 0 | int |
@@ -1855,3 +1861,9 @@ exprCfgNodeValue
| params/params.rb:65:41:65:42 | 99 | 99 | int |
| params/params.rb:70:42:70:45 | 1000 | 1000 | int |
| params/params.rb:70:52:70:53 | 20 | 20 | int |
| params/params.rb:100:15:100:15 | 1 | 1 | int |
| params/params.rb:101:15:101:15 | 1 | 1 | int |
| params/params.rb:107:5:107:9 | k | :k | symbol |
| params/params.rb:111:11:111:12 | 42 | 42 | int |
| params/params.rb:111:15:111:15 | :k | :k | symbol |
| params/params.rb:111:18:111:19 | 22 | 22 | int |

View File

@@ -39,6 +39,14 @@ idParams
| params.rb:86:14:86:14 | x | x |
| params.rb:89:31:89:35 | array | array |
| params.rb:94:36:94:39 | hash | hash |
| params.rb:99:9:99:9 | x | x |
| params.rb:99:12:99:16 | *rest | rest |
| params.rb:99:19:99:19 | k | k |
| params.rb:99:23:99:30 | **kwargs | kwargs |
| params.rb:106:9:106:9 | y | y |
| params.rb:106:12:106:16 | *rest | rest |
| params.rb:106:19:106:19 | k | k |
| params.rb:106:23:106:30 | **kwargs | kwargs |
blockParams
| params.rb:46:28:46:33 | &block | block |
| params.rb:62:29:62:34 | &block | block |
@@ -56,10 +64,14 @@ splatParams
| params.rb:30:31:30:36 | *splat | splat |
| params.rb:34:21:34:26 | *splat | splat |
| params.rb:38:29:38:33 | *blah | blah |
| params.rb:99:12:99:16 | *rest | rest |
| params.rb:106:12:106:16 | *rest | rest |
hashSplatParams
| params.rb:30:39:30:52 | **double_splat | double_splat |
| params.rb:34:29:34:42 | **double_splat | double_splat |
| params.rb:38:36:38:43 | **wibble | wibble |
| params.rb:99:23:99:30 | **kwargs | kwargs |
| params.rb:106:23:106:30 | **kwargs | kwargs |
keywordParams
| params.rb:41:35:41:37 | foo | foo | (none) |
| params.rb:41:41:41:43 | bar | bar | 7 |
@@ -67,6 +79,8 @@ keywordParams
| params.rb:49:33:49:34 | yy | yy | 100 |
| params.rb:53:37:53:37 | y | y | (none) |
| params.rb:53:41:53:41 | z | z | 3 |
| params.rb:99:19:99:19 | k | k | (none) |
| params.rb:106:19:106:19 | k | k | (none) |
optionalParams
| params.rb:58:39:58:42 | val2 | val2 | params.rb:58:46:58:46 | 0 |
| params.rb:58:49:58:52 | val3 | val3 | params.rb:58:56:58:58 | 100 |
@@ -97,6 +111,14 @@ paramsInMethods
| params.rb:89:1:91:3 | anonymous_splat_parameter | 1 | params.rb:89:38:89:38 | * | SplatParameter |
| params.rb:94:1:96:3 | anonymous_hash_splat_parameter | 0 | params.rb:94:36:94:39 | hash | SimpleParameter |
| params.rb:94:1:96:3 | anonymous_hash_splat_parameter | 1 | params.rb:94:42:94:43 | ** | HashSplatParameter |
| params.rb:99:3:102:5 | m | 0 | params.rb:99:9:99:9 | x | SimpleParameter |
| params.rb:99:3:102:5 | m | 1 | params.rb:99:12:99:16 | *rest | SplatParameter |
| params.rb:99:3:102:5 | m | 2 | params.rb:99:19:99:19 | k | KeywordParameter |
| params.rb:99:3:102:5 | m | 3 | params.rb:99:23:99:30 | **kwargs | HashSplatParameter |
| params.rb:106:3:108:5 | m | 0 | params.rb:106:9:106:9 | y | SimpleParameter |
| params.rb:106:3:108:5 | m | 1 | params.rb:106:12:106:16 | *rest | SplatParameter |
| params.rb:106:3:108:5 | m | 2 | params.rb:106:19:106:19 | k | KeywordParameter |
| params.rb:106:3:108:5 | m | 3 | params.rb:106:23:106:30 | **kwargs | HashSplatParameter |
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 |
@@ -175,3 +197,11 @@ params
| params.rb:89:38:89:38 | * | 1 | SplatParameter |
| params.rb:94:36:94:39 | hash | 0 | SimpleParameter |
| params.rb:94:42:94:43 | ** | 1 | HashSplatParameter |
| params.rb:99:9:99:9 | x | 0 | SimpleParameter |
| params.rb:99:12:99:16 | *rest | 1 | SplatParameter |
| params.rb:99:19:99:19 | k | 2 | KeywordParameter |
| params.rb:99:23:99:30 | **kwargs | 3 | HashSplatParameter |
| params.rb:106:9:106:9 | y | 0 | SimpleParameter |
| params.rb:106:12:106:16 | *rest | 1 | SplatParameter |
| params.rb:106:19:106:19 | k | 2 | KeywordParameter |
| params.rb:106:23:106:30 | **kwargs | 3 | HashSplatParameter |

View File

@@ -94,3 +94,18 @@ end
def anonymous_hash_splat_parameter(hash, **)
hash.merge(**)
end
class Sup
def m(x, *rest, k:, **kwargs)
print(x + 1)
print(k + 1)
end
end
class Sub < Sup
def m(y, *rest, k:, **kwargs)
super
end
end
Sub.new.m(42, k: 22)

File diff suppressed because it is too large Load Diff

View File

@@ -174,6 +174,34 @@ edges
| params_flow.rb:192:24:192:32 | call to taint | params_flow.rb:181:28:181:29 | p2 | provenance | |
| params_flow.rb:192:24:192:32 | call to taint | params_flow.rb:192:20:192:21 | [post] p1 : [collection] [element 0] | provenance | |
| params_flow.rb:193:6:193:7 | p1 : [collection] [element 0] | params_flow.rb:193:6:193:10 | ...[...] | provenance | |
| params_flow.rb:210:11:210:11 | x | params_flow.rb:211:14:211:14 | x | provenance | |
| params_flow.rb:210:14:210:18 | *rest : [collection] [element 0] | params_flow.rb:212:14:212:17 | rest : [collection] [element 0] | provenance | |
| params_flow.rb:210:14:210:18 | *rest : [collection] [element 2] | params_flow.rb:214:14:214:17 | rest : [collection] [element 2] | provenance | |
| params_flow.rb:210:21:210:22 | k1 | params_flow.rb:215:14:215:15 | k1 | provenance | |
| params_flow.rb:210:26:210:33 | **kwargs : Hash [element :k2] | params_flow.rb:216:14:216:19 | kwargs : Hash [element :k2] | provenance | |
| params_flow.rb:212:14:212:17 | rest : [collection] [element 0] | params_flow.rb:212:14:212:20 | ...[...] | provenance | |
| params_flow.rb:214:14:214:17 | rest : [collection] [element 2] | params_flow.rb:214:14:214:20 | ...[...] | provenance | |
| params_flow.rb:216:14:216:19 | kwargs : Hash [element :k2] | params_flow.rb:216:14:216:24 | ...[...] | provenance | |
| params_flow.rb:217:15:217:23 | call to taint | params_flow.rb:227:81:227:81 | x | provenance | |
| params_flow.rb:222:11:222:11 | x | params_flow.rb:223:9:223:13 | x | provenance | |
| params_flow.rb:222:14:222:18 | *rest : [collection] [element 0] | params_flow.rb:223:9:223:13 | rest : [collection] [element 0] | provenance | |
| params_flow.rb:222:14:222:18 | *rest : [collection] [element 2] | params_flow.rb:223:9:223:13 | rest : [collection] [element 2] | provenance | |
| params_flow.rb:222:21:222:22 | k1 | params_flow.rb:223:9:223:13 | k1 | provenance | |
| params_flow.rb:222:26:222:33 | **kwargs : Hash [element :k2] | params_flow.rb:223:9:223:13 | kwargs : Hash [element :k2] | provenance | |
| params_flow.rb:223:9:223:13 | * ... : [collection] [element 0] | params_flow.rb:210:14:210:18 | *rest : [collection] [element 0] | provenance | |
| params_flow.rb:223:9:223:13 | * ... : [collection] [element 2] | params_flow.rb:210:14:210:18 | *rest : [collection] [element 2] | provenance | |
| params_flow.rb:223:9:223:13 | ** ... : Hash [element :k2] | params_flow.rb:210:26:210:33 | **kwargs : Hash [element :k2] | provenance | |
| params_flow.rb:223:9:223:13 | k1 | params_flow.rb:210:21:210:22 | k1 | provenance | |
| params_flow.rb:223:9:223:13 | kwargs : Hash [element :k2] | params_flow.rb:223:9:223:13 | ** ... : Hash [element :k2] | provenance | |
| params_flow.rb:223:9:223:13 | rest : [collection] [element 0] | params_flow.rb:223:9:223:13 | * ... : [collection] [element 0] | provenance | |
| params_flow.rb:223:9:223:13 | rest : [collection] [element 2] | params_flow.rb:223:9:223:13 | * ... : [collection] [element 2] | provenance | |
| params_flow.rb:223:9:223:13 | x | params_flow.rb:210:11:210:11 | x | provenance | |
| params_flow.rb:227:11:227:19 | call to taint | params_flow.rb:222:11:222:11 | x | provenance | |
| params_flow.rb:227:22:227:30 | call to taint | params_flow.rb:222:14:222:18 | *rest : [collection] [element 0] | provenance | |
| params_flow.rb:227:36:227:44 | call to taint | params_flow.rb:222:14:222:18 | *rest : [collection] [element 2] | provenance | |
| params_flow.rb:227:51:227:59 | call to taint | params_flow.rb:222:21:222:22 | k1 | provenance | |
| params_flow.rb:227:66:227:74 | call to taint | params_flow.rb:222:26:222:33 | **kwargs : Hash [element :k2] | provenance | |
| params_flow.rb:227:81:227:81 | x | params_flow.rb:228:10:228:10 | x | provenance | |
nodes
| params_flow.rb:9:16:9:17 | p1 | semmle.label | p1 |
| params_flow.rb:9:20:9:21 | p2 | semmle.label | p2 |
@@ -373,6 +401,40 @@ nodes
| params_flow.rb:192:24:192:32 | call to taint | semmle.label | call to taint |
| params_flow.rb:193:6:193:7 | p1 : [collection] [element 0] | semmle.label | p1 : [collection] [element 0] |
| params_flow.rb:193:6:193:10 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:210:11:210:11 | x | semmle.label | x |
| params_flow.rb:210:14:210:18 | *rest : [collection] [element 0] | semmle.label | *rest : [collection] [element 0] |
| params_flow.rb:210:14:210:18 | *rest : [collection] [element 2] | semmle.label | *rest : [collection] [element 2] |
| params_flow.rb:210:21:210:22 | k1 | semmle.label | k1 |
| params_flow.rb:210:26:210:33 | **kwargs : Hash [element :k2] | semmle.label | **kwargs : Hash [element :k2] |
| params_flow.rb:211:14:211:14 | x | semmle.label | x |
| params_flow.rb:212:14:212:17 | rest : [collection] [element 0] | semmle.label | rest : [collection] [element 0] |
| params_flow.rb:212:14:212:20 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:214:14:214:17 | rest : [collection] [element 2] | semmle.label | rest : [collection] [element 2] |
| params_flow.rb:214:14:214:20 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:215:14:215:15 | k1 | semmle.label | k1 |
| params_flow.rb:216:14:216:19 | kwargs : Hash [element :k2] | semmle.label | kwargs : Hash [element :k2] |
| params_flow.rb:216:14:216:24 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:217:15:217:23 | call to taint | semmle.label | call to taint |
| params_flow.rb:222:11:222:11 | x | semmle.label | x |
| params_flow.rb:222:14:222:18 | *rest : [collection] [element 0] | semmle.label | *rest : [collection] [element 0] |
| params_flow.rb:222:14:222:18 | *rest : [collection] [element 2] | semmle.label | *rest : [collection] [element 2] |
| params_flow.rb:222:21:222:22 | k1 | semmle.label | k1 |
| params_flow.rb:222:26:222:33 | **kwargs : Hash [element :k2] | semmle.label | **kwargs : Hash [element :k2] |
| params_flow.rb:223:9:223:13 | * ... : [collection] [element 0] | semmle.label | * ... : [collection] [element 0] |
| params_flow.rb:223:9:223:13 | * ... : [collection] [element 2] | semmle.label | * ... : [collection] [element 2] |
| params_flow.rb:223:9:223:13 | ** ... : Hash [element :k2] | semmle.label | ** ... : Hash [element :k2] |
| params_flow.rb:223:9:223:13 | k1 | semmle.label | k1 |
| params_flow.rb:223:9:223:13 | kwargs : Hash [element :k2] | semmle.label | kwargs : Hash [element :k2] |
| params_flow.rb:223:9:223:13 | rest : [collection] [element 0] | semmle.label | rest : [collection] [element 0] |
| params_flow.rb:223:9:223:13 | rest : [collection] [element 2] | semmle.label | rest : [collection] [element 2] |
| params_flow.rb:223:9:223:13 | x | semmle.label | x |
| params_flow.rb:227:11:227:19 | call to taint | semmle.label | call to taint |
| params_flow.rb:227:22:227:30 | call to taint | semmle.label | call to taint |
| params_flow.rb:227:36:227:44 | call to taint | semmle.label | call to taint |
| params_flow.rb:227:51:227:59 | call to taint | semmle.label | call to taint |
| params_flow.rb:227:66:227:74 | call to taint | semmle.label | call to taint |
| params_flow.rb:227:81:227:81 | x | semmle.label | x |
| params_flow.rb:228:10:228:10 | x | semmle.label | x |
subpaths
| params_flow.rb:164:31:164:39 | call to taint | params_flow.rb:153:28:153:29 | p2 | params_flow.rb:153:23:153:24 | p1 [Return] : [collection] [element 0] | params_flow.rb:164:23:164:24 | [post] p1 : [collection] [element 0] |
| params_flow.rb:192:24:192:32 | call to taint | params_flow.rb:181:28:181:29 | p2 | params_flow.rb:181:24:181:25 | p1 [Return] : [collection] [element 0] | params_flow.rb:192:20:192:21 | [post] p1 : [collection] [element 0] |
@@ -430,3 +492,9 @@ testFailures
| params_flow.rb:134:10:134:16 | ...[...] | params_flow.rb:137:23:137:31 | call to taint | params_flow.rb:134:10:134:16 | ...[...] | $@ | params_flow.rb:137:23:137:31 | call to taint | call to taint |
| params_flow.rb:165:6:165:10 | ...[...] | params_flow.rb:164:31:164:39 | call to taint | params_flow.rb:165:6:165:10 | ...[...] | $@ | params_flow.rb:164:31:164:39 | call to taint | call to taint |
| params_flow.rb:193:6:193:10 | ...[...] | params_flow.rb:192:24:192:32 | call to taint | params_flow.rb:193:6:193:10 | ...[...] | $@ | params_flow.rb:192:24:192:32 | call to taint | call to taint |
| params_flow.rb:211:14:211:14 | x | params_flow.rb:227:11:227:19 | call to taint | params_flow.rb:211:14:211:14 | x | $@ | params_flow.rb:227:11:227:19 | call to taint | call to taint |
| params_flow.rb:212:14:212:20 | ...[...] | params_flow.rb:227:22:227:30 | call to taint | params_flow.rb:212:14:212:20 | ...[...] | $@ | params_flow.rb:227:22:227:30 | call to taint | call to taint |
| params_flow.rb:214:14:214:20 | ...[...] | params_flow.rb:227:36:227:44 | call to taint | params_flow.rb:214:14:214:20 | ...[...] | $@ | params_flow.rb:227:36:227:44 | call to taint | call to taint |
| params_flow.rb:215:14:215:15 | k1 | params_flow.rb:227:51:227:59 | call to taint | params_flow.rb:215:14:215:15 | k1 | $@ | params_flow.rb:227:51:227:59 | call to taint | call to taint |
| params_flow.rb:216:14:216:24 | ...[...] | params_flow.rb:227:66:227:74 | call to taint | params_flow.rb:216:14:216:24 | ...[...] | $@ | params_flow.rb:227:66:227:74 | call to taint | call to taint |
| params_flow.rb:228:10:228:10 | x | params_flow.rb:217:15:217:23 | call to taint | params_flow.rb:228:10:228:10 | x | $@ | params_flow.rb:217:15:217:23 | call to taint | call to taint |

View File

@@ -205,3 +205,25 @@ def foo(x, y)
end
foo(*int_hash)
class Sup
def m(x, *rest, k1:, **kwargs)
sink(x) # $ hasValueFlow=81
sink(rest[0]) # $ hasValueFlow=82
sink(rest[1])
sink(rest[2]) # $ hasValueFlow=83
sink(k1) # $ hasValueFlow=84
sink(kwargs[:k2]) # $ hasValueFlow=85
yield taint(86)
end
end
class Sub < Sup
def m(x, *rest, k1:, **kwargs)
super
end
end
Sub.new.m(taint(81), taint(82), 0, taint(83), k1: taint(84), k2: taint(85)) do |x|
sink(x) # $ hasValueFlow=86
end