mirror of
https://github.com/github/codeql.git
synced 2026-05-25 00:27:09 +02:00
Merge tag 'codeql-cli/latest' into auto/sync-main-pr
Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
@@ -8,30 +8,18 @@ private import codeql.dataflow.internal.DataFlowImplConsistency
|
||||
private module Input implements InputSig<Location, RubyDataFlow> {
|
||||
private import RubyDataFlow
|
||||
|
||||
predicate postWithInFlowExclude(Node n) { n instanceof FlowSummaryNode }
|
||||
predicate postWithInFlowExclude(Node n) {
|
||||
n instanceof FlowSummaryNode
|
||||
or
|
||||
n.(PostUpdateNode).getPreUpdateNode().asExpr() = getPostUpdateReverseStep(_)
|
||||
}
|
||||
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||
n instanceof FlowSummaryNode
|
||||
or
|
||||
n instanceof SynthHashSplatArgumentNode
|
||||
or
|
||||
not isNonConstantExpr(getAPostUpdateNodeForArg(n.asExpr()))
|
||||
}
|
||||
|
||||
predicate postHasUniquePreExclude(PostUpdateNode n) {
|
||||
exists(CfgNodes::ExprCfgNode e, CfgNodes::ExprCfgNode arg |
|
||||
e = getAPostUpdateNodeForArg(arg) and
|
||||
e != arg and
|
||||
n = TExprPostUpdateNode(e)
|
||||
)
|
||||
}
|
||||
|
||||
predicate uniquePostUpdateExclude(Node n) {
|
||||
exists(CfgNodes::ExprCfgNode e, CfgNodes::ExprCfgNode arg |
|
||||
e = getAPostUpdateNodeForArg(arg) and
|
||||
e != arg and
|
||||
n.asExpr() = arg
|
||||
)
|
||||
not isNonConstantExpr(n.asExpr())
|
||||
}
|
||||
|
||||
predicate multipleArgumentCallExclude(ArgumentNode arg, DataFlowCall call) {
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 4.1.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* 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)`.
|
||||
|
||||
## 4.1.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
5
ruby/ql/lib/change-notes/released/4.1.4.md
Normal file
5
ruby/ql/lib/change-notes/released/4.1.4.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 4.1.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* 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)`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 4.1.3
|
||||
lastReleaseVersion: 4.1.4
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 { }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -66,10 +67,22 @@ private CfgNodes::ExprCfgNode getALastEvalNode(CfgNodes::ExprCfgNode n) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a node for which to construct a post-update node for argument `arg`. */
|
||||
CfgNodes::ExprCfgNode getAPostUpdateNodeForArg(Argument arg) {
|
||||
result = getALastEvalNode*(arg) and
|
||||
not exists(getALastEvalNode(result))
|
||||
/**
|
||||
* Holds if a reverse local flow step should be added from the post-update node
|
||||
* for `e` to the post-update node for the result.
|
||||
*
|
||||
* This is needed to allow for side-effects on compound expressions to propagate
|
||||
* to sub components. For example, in
|
||||
*
|
||||
* ```ruby
|
||||
* (foo1; foo2).set_field(taint)
|
||||
* ```
|
||||
*
|
||||
* we add a reverse flow step from `[post] (foo1; foo2)` to `[post] foo2`,
|
||||
* in order for the side-effect of `set_field` to reach `foo2`.
|
||||
*/
|
||||
CfgNodes::ExprCfgNode getPostUpdateReverseStep(CfgNodes::ExprCfgNode e) {
|
||||
result = getALastEvalNode(e)
|
||||
}
|
||||
|
||||
/** Gets the SSA definition node corresponding to parameter `p`. */
|
||||
@@ -170,6 +183,9 @@ module LocalFlow {
|
||||
)
|
||||
or
|
||||
nodeTo.(ImplicitBlockArgumentNode).getParameterNode(true) = nodeFrom
|
||||
or
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() =
|
||||
getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr())
|
||||
}
|
||||
|
||||
predicate flowSummaryLocalStep(
|
||||
@@ -468,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
|
||||
@@ -486,7 +505,9 @@ private module Cached {
|
||||
// filter out nodes that clearly don't need post-update nodes
|
||||
isNonConstantExpr(n) and
|
||||
(
|
||||
n = getAPostUpdateNodeForArg(_)
|
||||
n instanceof Argument
|
||||
or
|
||||
n = getPostUpdateReverseStep(any(PostUpdateNode p).getPreUpdateNode().asExpr())
|
||||
or
|
||||
n = any(CfgNodes::ExprNodes::InstanceVariableAccessCfgNode v).getReceiver()
|
||||
)
|
||||
@@ -1032,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 {
|
||||
@@ -1298,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
|
||||
@@ -1326,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 {
|
||||
@@ -2018,18 +2080,7 @@ private module PostUpdateNodes {
|
||||
|
||||
ExprPostUpdateNode() { this = TExprPostUpdateNode(e) }
|
||||
|
||||
override ExprNode getPreUpdateNode() {
|
||||
// For compound arguments, such as `m(if b then x else y)`, we want the leaf nodes
|
||||
// `[post] x` and `[post] y` to have two pre-update nodes: (1) the compound argument,
|
||||
// `if b then x else y`; and the (2) the underlying expressions; `x` and `y`,
|
||||
// respectively.
|
||||
//
|
||||
// This ensures that we get flow out of the call into both leafs (1), while still
|
||||
// maintaining the invariant that the underlying expression is a pre-update node (2).
|
||||
e = getAPostUpdateNodeForArg(result.getExprNode())
|
||||
or
|
||||
e = result.getExprNode()
|
||||
}
|
||||
override ExprNode getPreUpdateNode() { e = result.getExprNode() }
|
||||
|
||||
override CfgScope getCfgScope() { result = e.getExpr().getCfgScope() }
|
||||
|
||||
@@ -2152,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())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/ruby-all
|
||||
version: 4.1.3
|
||||
version: 4.1.4
|
||||
groups: ruby
|
||||
extractor: ruby
|
||||
dbscheme: ruby.dbscheme
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## 1.2.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The query `rb/useless-assignment-to-local` now comes with query help and has been tweaked to produce fewer false positives.
|
||||
* The query `rb/uninitialized-local-variable` now only produces alerts when the variable is the receiver of a method call and should produce very few false positives. It also now comes with a help file.
|
||||
|
||||
## 1.1.15
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
6
ruby/ql/src/change-notes/released/1.2.0.md
Normal file
6
ruby/ql/src/change-notes/released/1.2.0.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 1.2.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The query `rb/useless-assignment-to-local` now comes with query help and has been tweaked to produce fewer false positives.
|
||||
* The query `rb/uninitialized-local-variable` now only produces alerts when the variable is the receiver of a method call and should produce very few false positives. It also now comes with a help file.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.1.15
|
||||
lastReleaseVersion: 1.2.0
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
- queries: .
|
||||
- include:
|
||||
id:
|
||||
- rb/database-query-in-loop
|
||||
- rb/database-query-in-loop
|
||||
- rb/useless-assignment-to-local
|
||||
- rb/uninitialized-local-variable
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/ruby-queries
|
||||
version: 1.1.15
|
||||
version: 1.2.0
|
||||
groups:
|
||||
- ruby
|
||||
- queries
|
||||
|
||||
49
ruby/ql/src/queries/variables/DeadStoreOfLocal.qhelp
Normal file
49
ruby/ql/src/queries/variables/DeadStoreOfLocal.qhelp
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
A value is assigned to a local variable, but either that variable is never read
|
||||
later on, or its value is always overwritten before being read. This means
|
||||
that the original assignment has no effect, and could indicate a logic error or
|
||||
incomplete code.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Ensure that you check the control and data flow in the method carefully.
|
||||
If a value is really not needed, consider omitting the assignment. Be careful,
|
||||
though: if the right-hand side has a side-effect (like performing a method call),
|
||||
it is important to keep this to preserve the overall behavior.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
In the following example, the return value of the call to <code>send</code> on line 2
|
||||
is assigned to the local variable <code>result</code>, but then never used.
|
||||
</p>
|
||||
|
||||
<sample src="examples/DeadStoreOfLocal.rb" />
|
||||
|
||||
<p>
|
||||
Assuming that <code>send</code> returns a status code indicating whether the operation
|
||||
succeeded or not, the value of <code>result</code> should be checked, perhaps like this:
|
||||
</p>
|
||||
|
||||
<sample src="examples/DeadStoreOfLocalGood.rb" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
|
||||
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Dead_store">Dead store</a>.</li>
|
||||
|
||||
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -7,16 +7,30 @@
|
||||
* @id rb/useless-assignment-to-local
|
||||
* @tags maintainability
|
||||
* external/cwe/cwe-563
|
||||
* @precision low
|
||||
* @precision medium
|
||||
*/
|
||||
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.CFG
|
||||
import codeql.ruby.dataflow.SSA
|
||||
import codeql.ruby.ApiGraphs
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasErbResultCall(CfgScope scope) {
|
||||
scope = API::getTopLevelMember("ERB").getInstance().getAMethodCall("result").asExpr().getScope()
|
||||
}
|
||||
|
||||
class RelevantLocalVariableWriteAccess extends LocalVariableWriteAccess {
|
||||
RelevantLocalVariableWriteAccess() {
|
||||
not this.getVariable().getName().charAt(0) = "_" and
|
||||
not this = any(Parameter p).getAVariable().getDefiningAccess()
|
||||
not this = any(Parameter p).getAVariable().getDefiningAccess() and
|
||||
not hasErbResultCall(this.getCfgScope()) and
|
||||
not exists(RetryStmt r | r.getCfgScope() = this.getCfgScope()) and
|
||||
not exists(MethodCall c |
|
||||
c.getReceiver() instanceof SelfVariableAccess and
|
||||
c.getMethodName() = "binding" and
|
||||
c.getCfgScope() = this.getCfgScope()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
41
ruby/ql/src/queries/variables/UninitializedLocal.md
Normal file
41
ruby/ql/src/queries/variables/UninitializedLocal.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Method call on `nil`
|
||||
|
||||
## Description
|
||||
In Ruby, it is not necessary to explicitly initialize variables.
|
||||
If a local variable has not been explicitly initialized, it will have the value `nil`. If this happens unintended, though, the variable will not represent an object with the expected methods, and a method call on the variable will raise a `NoMethodError`.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Ensure that the variable cannot be `nil` at the point hightligted by the alert.
|
||||
This can be achieved by using a safe navigation or adding a check for `nil`.
|
||||
|
||||
Note: You do not need to explicitly initialize the variable, if you can make the program deal with the possible `nil` value. In particular, initializing the variable to `nil` will have no effect, as this is already the value of the variable. If `nil` is the only possibly default value, you need to handle the `nil` value instead of initializing the variable.
|
||||
|
||||
## Examples
|
||||
|
||||
In the following code, the call to `create_file` may fail and then the call `f.close` will raise a `NoMethodError` since `f` will be `nil` at that point.
|
||||
|
||||
```ruby
|
||||
def dump(x)
|
||||
f = create_file
|
||||
f.puts(x)
|
||||
ensure
|
||||
f.close
|
||||
end
|
||||
```
|
||||
|
||||
We can fix this by using safe navigation:
|
||||
```ruby
|
||||
def dump(x)
|
||||
f = create_file
|
||||
f.puts(x)
|
||||
ensure
|
||||
f&.close
|
||||
end
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- https://www.rubyguides.com/: [Nil](https://www.rubyguides.com/2018/01/ruby-nil/)
|
||||
- https://ruby-doc.org/: [NoMethodError](https://ruby-doc.org/core-2.6.5/NoMethodError.html)
|
||||
|
||||
@@ -5,20 +5,91 @@
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @id rb/uninitialized-local-variable
|
||||
* @tags reliability
|
||||
* @tags quality
|
||||
* reliability
|
||||
* correctness
|
||||
* @precision low
|
||||
* @precision high
|
||||
*/
|
||||
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.dataflow.SSA
|
||||
import codeql.ruby.controlflow.internal.Guards as Guards
|
||||
import codeql.ruby.controlflow.CfgNodes
|
||||
import codeql.ruby.ast.internal.Variable
|
||||
|
||||
class RelevantLocalVariableReadAccess extends LocalVariableReadAccess {
|
||||
RelevantLocalVariableReadAccess() {
|
||||
not exists(MethodCall c |
|
||||
c.getReceiver() = this and
|
||||
private predicate isInBooleanContext(AstNode n) {
|
||||
exists(ConditionalExpr i |
|
||||
n = i.getCondition()
|
||||
or
|
||||
isInBooleanContext(i) and
|
||||
n = i.getBranch(_)
|
||||
)
|
||||
or
|
||||
n = any(ConditionalLoop parent).getCondition()
|
||||
or
|
||||
n = any(InClause parent).getCondition()
|
||||
or
|
||||
n = any(LogicalAndExpr op).getAnOperand()
|
||||
or
|
||||
n = any(LogicalOrExpr op).getAnOperand()
|
||||
or
|
||||
n = any(NotExpr op).getOperand()
|
||||
or
|
||||
n = any(StmtSequence parent | isInBooleanContext(parent)).getLastStmt()
|
||||
or
|
||||
exists(CaseExpr c, WhenClause w |
|
||||
not exists(c.getValue()) and
|
||||
c.getABranch() = w
|
||||
|
|
||||
w.getPattern(_) = n
|
||||
or
|
||||
w = n
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isGuarded(LocalVariableReadAccess read) {
|
||||
exists(AstCfgNode guard, boolean branch |
|
||||
Guards::guardControlsBlock(guard, read.getAControlFlowNode().getBasicBlock(), branch)
|
||||
|
|
||||
// guard is `var`
|
||||
guard.getAstNode() = read.getVariable().getAnAccess() and
|
||||
branch = true
|
||||
or
|
||||
// guard is `var.nil?`
|
||||
exists(MethodCall c | guard.getAstNode() = c |
|
||||
c.getReceiver() = read.getVariable().getAnAccess() and
|
||||
c.getMethodName() = "nil?"
|
||||
)
|
||||
) and
|
||||
branch = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isNilChecked(LocalVariableReadAccess read) {
|
||||
exists(MethodCall c | c.getReceiver() = read |
|
||||
c.getMethodName() = "nil?"
|
||||
or
|
||||
c.isSafeNavigation()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is the name of a method defined on `nil`.
|
||||
* See https://ruby-doc.org/core-2.5.8/NilClass.html
|
||||
*/
|
||||
private predicate isNilMethodName(string name) {
|
||||
name in [
|
||||
"inspect", "instance_of?", "is_a?", "kind_of?", "method", "nil?", "rationalize", "to_a",
|
||||
"to_c", "to_f", "to_h", "to_i", "to_r", "to_s"
|
||||
]
|
||||
}
|
||||
|
||||
class RelevantLocalVariableReadAccess extends LocalVariableReadAccess instanceof TVariableAccessReal
|
||||
{
|
||||
RelevantLocalVariableReadAccess() {
|
||||
not isInBooleanContext(this) and
|
||||
not isNilChecked(this) and
|
||||
not isGuarded(this) and
|
||||
this = any(MethodCall m | not isNilMethodName(m.getMethodName())).getReceiver()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
def f(x)
|
||||
result = send(x)
|
||||
waitForResponse
|
||||
return getResponse
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
def f(x)
|
||||
result = send(x)
|
||||
# check for error
|
||||
if (result == -1)
|
||||
raise "Unable to send, check network."
|
||||
end
|
||||
waitForResponse
|
||||
return getResponse
|
||||
end
|
||||
14
ruby/ql/src/queries/variables/examples/UninitializedLocal.rb
Normal file
14
ruby/ql/src/queries/variables/examples/UninitializedLocal.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
def m
|
||||
puts "m"
|
||||
end
|
||||
|
||||
def foo
|
||||
m # calls m above
|
||||
if false
|
||||
m = "0"
|
||||
m # reads local variable m
|
||||
else
|
||||
end
|
||||
m.strip # reads uninitialized local variable m, `nil`, and crashes
|
||||
m2 # undefined local variable or method 'm2' for main (NameError)
|
||||
end
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
@@ -197,18 +197,18 @@ edges
|
||||
| instance_variables.rb:70:16:70:24 | call to taint | instance_variables.rb:10:19:10:19 | x | provenance | |
|
||||
| instance_variables.rb:70:16:70:24 | call to taint | instance_variables.rb:70:1:70:4 | [post] foo3 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:71:6:71:9 | foo3 : Foo [@field] | instance_variables.rb:71:6:71:15 | call to field | provenance | |
|
||||
| instance_variables.rb:78:2:78:5 | [post] foo5 : Foo [@field] | instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:78:2:78:5 | [post] foo5 : Foo [@field] | instance_variables.rb:84:6:84:9 | foo5 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:78:1:78:6 | [post] ( ... ) : Foo [@field] | instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:78:1:78:6 | [post] ( ... ) : Foo [@field] | instance_variables.rb:84:6:84:9 | foo5 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | captured_variables.rb:57:19:57:19 | x | provenance | |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | instance_variables.rb:10:19:10:19 | x | provenance | |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | instance_variables.rb:78:2:78:5 | [post] foo5 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | instance_variables.rb:78:1:78:6 | [post] ( ... ) : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | instance_variables.rb:79:6:79:19 | call to get_field | provenance | |
|
||||
| instance_variables.rb:82:15:82:18 | [post] foo6 : Foo [@field] | instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:82:1:82:20 | [post] ( ... ) : Foo [@field] | instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | captured_variables.rb:57:19:57:19 | x | provenance | |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | instance_variables.rb:10:19:10:19 | x | provenance | |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | instance_variables.rb:82:15:82:18 | [post] foo6 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | instance_variables.rb:82:1:82:20 | [post] ( ... ) : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:83:6:83:9 | foo3 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:83:6:83:9 | foo3 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:83:6:83:9 | foo3 : Foo [@field] | instance_variables.rb:83:6:83:19 | call to get_field | provenance | |
|
||||
@@ -218,24 +218,22 @@ edges
|
||||
| instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | instance_variables.rb:85:6:85:19 | call to get_field | provenance | |
|
||||
| instance_variables.rb:89:15:89:18 | [post] foo7 : Foo [@field] | instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:89:25:89:28 | [post] foo8 : Foo [@field] | instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:89:1:89:33 | [post] ( ... ) : Foo [@field] | instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:89:1:89:33 | [post] ( ... ) : Foo [@field] | instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | captured_variables.rb:57:19:57:19 | x | provenance | |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:10:19:10:19 | x | provenance | |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:89:15:89:18 | [post] foo7 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:89:25:89:28 | [post] foo8 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:89:1:89:33 | [post] ( ... ) : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | instance_variables.rb:90:6:90:19 | call to get_field | provenance | |
|
||||
| instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | instance_variables.rb:91:6:91:19 | call to get_field | provenance | |
|
||||
| instance_variables.rb:95:22:95:25 | [post] foo9 : Foo [@field] | instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:95:32:95:36 | [post] foo10 : Foo [@field] | instance_variables.rb:97:6:97:10 | foo10 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:95:1:95:41 | [post] ( ... ) : Foo [@field] | instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:95:1:95:41 | [post] ( ... ) : Foo [@field] | instance_variables.rb:97:6:97:10 | foo10 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | captured_variables.rb:57:19:57:19 | x | provenance | |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:10:19:10:19 | x | provenance | |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:95:22:95:25 | [post] foo9 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:95:32:95:36 | [post] foo10 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:95:1:95:41 | [post] ( ... ) : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | instance_variables.rb:96:6:96:19 | call to get_field | provenance | |
|
||||
@@ -243,8 +241,8 @@ edges
|
||||
| instance_variables.rb:97:6:97:10 | foo10 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:97:6:97:10 | foo10 : Foo [@field] | instance_variables.rb:97:6:97:20 | call to get_field | provenance | |
|
||||
| instance_variables.rb:99:18:99:18 | x [Return] : Foo [@field] | instance_variables.rb:104:14:104:18 | [post] foo11 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:99:18:99:18 | x [Return] : Foo [@field] | instance_variables.rb:108:15:108:19 | [post] foo12 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:99:18:99:18 | x [Return] : Foo [@field] | instance_variables.rb:113:22:113:26 | [post] foo13 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:99:18:99:18 | x [Return] : Foo [@field] | instance_variables.rb:108:14:108:20 | [post] ( ... ) : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:99:18:99:18 | x [Return] : Foo [@field] | instance_variables.rb:113:14:113:26 | [post] ... = ... : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:100:5:100:5 | [post] x : Foo [@field] | instance_variables.rb:99:18:99:18 | x [Return] : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:100:17:100:25 | call to taint | captured_variables.rb:57:19:57:19 | x | provenance | |
|
||||
| instance_variables.rb:100:17:100:25 | call to taint | instance_variables.rb:10:19:10:19 | x | provenance | |
|
||||
@@ -253,11 +251,11 @@ edges
|
||||
| instance_variables.rb:105:6:105:10 | foo11 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:105:6:105:10 | foo11 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:105:6:105:10 | foo11 : Foo [@field] | instance_variables.rb:105:6:105:20 | call to get_field | provenance | |
|
||||
| instance_variables.rb:108:15:108:19 | [post] foo12 : Foo [@field] | instance_variables.rb:109:6:109:10 | foo12 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:108:14:108:20 | [post] ( ... ) : Foo [@field] | instance_variables.rb:109:6:109:10 | foo12 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:109:6:109:10 | foo12 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:109:6:109:10 | foo12 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:109:6:109:10 | foo12 : Foo [@field] | instance_variables.rb:109:6:109:20 | call to get_field | provenance | |
|
||||
| instance_variables.rb:113:22:113:26 | [post] foo13 : Foo [@field] | instance_variables.rb:114:6:114:10 | foo13 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:113:14:113:26 | [post] ... = ... : Foo [@field] | instance_variables.rb:114:6:114:10 | foo13 : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:114:6:114:10 | foo13 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:114:6:114:10 | foo13 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | provenance | |
|
||||
| instance_variables.rb:114:6:114:10 | foo13 : Foo [@field] | instance_variables.rb:114:6:114:20 | call to get_field | provenance | |
|
||||
@@ -475,11 +473,11 @@ nodes
|
||||
| instance_variables.rb:70:16:70:24 | call to taint | semmle.label | call to taint |
|
||||
| instance_variables.rb:71:6:71:9 | foo3 : Foo [@field] | semmle.label | foo3 : Foo [@field] |
|
||||
| instance_variables.rb:71:6:71:15 | call to field | semmle.label | call to field |
|
||||
| instance_variables.rb:78:2:78:5 | [post] foo5 : Foo [@field] | semmle.label | [post] foo5 : Foo [@field] |
|
||||
| instance_variables.rb:78:1:78:6 | [post] ( ... ) : Foo [@field] | semmle.label | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | semmle.label | call to taint |
|
||||
| instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | semmle.label | foo5 : Foo [@field] |
|
||||
| instance_variables.rb:79:6:79:19 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:82:15:82:18 | [post] foo6 : Foo [@field] | semmle.label | [post] foo6 : Foo [@field] |
|
||||
| instance_variables.rb:82:1:82:20 | [post] ( ... ) : Foo [@field] | semmle.label | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | semmle.label | call to taint |
|
||||
| instance_variables.rb:83:6:83:9 | foo3 : Foo [@field] | semmle.label | foo3 : Foo [@field] |
|
||||
| instance_variables.rb:83:6:83:19 | call to get_field | semmle.label | call to get_field |
|
||||
@@ -487,15 +485,13 @@ nodes
|
||||
| instance_variables.rb:84:6:84:19 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | semmle.label | foo6 : Foo [@field] |
|
||||
| instance_variables.rb:85:6:85:19 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:89:15:89:18 | [post] foo7 : Foo [@field] | semmle.label | [post] foo7 : Foo [@field] |
|
||||
| instance_variables.rb:89:25:89:28 | [post] foo8 : Foo [@field] | semmle.label | [post] foo8 : Foo [@field] |
|
||||
| instance_variables.rb:89:1:89:33 | [post] ( ... ) : Foo [@field] | semmle.label | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | semmle.label | call to taint |
|
||||
| instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | semmle.label | foo7 : Foo [@field] |
|
||||
| instance_variables.rb:90:6:90:19 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | semmle.label | foo8 : Foo [@field] |
|
||||
| instance_variables.rb:91:6:91:19 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:95:22:95:25 | [post] foo9 : Foo [@field] | semmle.label | [post] foo9 : Foo [@field] |
|
||||
| instance_variables.rb:95:32:95:36 | [post] foo10 : Foo [@field] | semmle.label | [post] foo10 : Foo [@field] |
|
||||
| instance_variables.rb:95:1:95:41 | [post] ( ... ) : Foo [@field] | semmle.label | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | semmle.label | call to taint |
|
||||
| instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | semmle.label | foo9 : Foo [@field] |
|
||||
| instance_variables.rb:96:6:96:19 | call to get_field | semmle.label | call to get_field |
|
||||
@@ -507,10 +503,10 @@ nodes
|
||||
| instance_variables.rb:104:14:104:18 | [post] foo11 : Foo [@field] | semmle.label | [post] foo11 : Foo [@field] |
|
||||
| instance_variables.rb:105:6:105:10 | foo11 : Foo [@field] | semmle.label | foo11 : Foo [@field] |
|
||||
| instance_variables.rb:105:6:105:20 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:108:15:108:19 | [post] foo12 : Foo [@field] | semmle.label | [post] foo12 : Foo [@field] |
|
||||
| instance_variables.rb:108:14:108:20 | [post] ( ... ) : Foo [@field] | semmle.label | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:109:6:109:10 | foo12 : Foo [@field] | semmle.label | foo12 : Foo [@field] |
|
||||
| instance_variables.rb:109:6:109:20 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:113:22:113:26 | [post] foo13 : Foo [@field] | semmle.label | [post] foo13 : Foo [@field] |
|
||||
| instance_variables.rb:113:14:113:26 | [post] ... = ... : Foo [@field] | semmle.label | [post] ... = ... : Foo [@field] |
|
||||
| instance_variables.rb:114:6:114:10 | foo13 : Foo [@field] | semmle.label | foo13 : Foo [@field] |
|
||||
| instance_variables.rb:114:6:114:20 | call to get_field | semmle.label | call to get_field |
|
||||
| instance_variables.rb:116:1:116:5 | foo15 : Foo [@field] | semmle.label | foo15 : Foo [@field] |
|
||||
@@ -565,30 +561,26 @@ subpaths
|
||||
| instance_variables.rb:67:6:67:9 | foo2 [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:67:6:67:19 | call to get_field |
|
||||
| instance_variables.rb:70:16:70:24 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:70:1:70:4 | [post] foo3 : Foo [@field] |
|
||||
| instance_variables.rb:70:16:70:24 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:70:1:70:4 | [post] foo3 : Foo [@field] |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:78:2:78:5 | [post] foo5 : Foo [@field] |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:78:2:78:5 | [post] foo5 : Foo [@field] |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:78:1:78:6 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:78:18:78:26 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:78:1:78:6 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:79:6:79:19 | call to get_field |
|
||||
| instance_variables.rb:79:6:79:9 | foo5 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:79:6:79:19 | call to get_field |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:82:15:82:18 | [post] foo6 : Foo [@field] |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:82:15:82:18 | [post] foo6 : Foo [@field] |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:82:1:82:20 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:82:32:82:40 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:82:1:82:20 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:83:6:83:9 | foo3 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:83:6:83:19 | call to get_field |
|
||||
| instance_variables.rb:83:6:83:9 | foo3 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:83:6:83:19 | call to get_field |
|
||||
| instance_variables.rb:84:6:84:9 | foo5 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:84:6:84:19 | call to get_field |
|
||||
| instance_variables.rb:84:6:84:9 | foo5 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:84:6:84:19 | call to get_field |
|
||||
| instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:85:6:85:19 | call to get_field |
|
||||
| instance_variables.rb:85:6:85:9 | foo6 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:85:6:85:19 | call to get_field |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:89:15:89:18 | [post] foo7 : Foo [@field] |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:89:25:89:28 | [post] foo8 : Foo [@field] |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:89:15:89:18 | [post] foo7 : Foo [@field] |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:89:25:89:28 | [post] foo8 : Foo [@field] |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:89:1:89:33 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:89:45:89:53 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:89:1:89:33 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:90:6:90:19 | call to get_field |
|
||||
| instance_variables.rb:90:6:90:9 | foo7 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:90:6:90:19 | call to get_field |
|
||||
| instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:91:6:91:19 | call to get_field |
|
||||
| instance_variables.rb:91:6:91:9 | foo8 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:91:6:91:19 | call to get_field |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:95:22:95:25 | [post] foo9 : Foo [@field] |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:95:32:95:36 | [post] foo10 : Foo [@field] |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:95:22:95:25 | [post] foo9 : Foo [@field] |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:95:32:95:36 | [post] foo10 : Foo [@field] |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:57:5:59:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:95:1:95:41 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:95:53:95:61 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:10:5:12:7 | self in set_field [Return] : Foo [@field] | instance_variables.rb:95:1:95:41 | [post] ( ... ) : Foo [@field] |
|
||||
| instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:96:6:96:19 | call to get_field |
|
||||
| instance_variables.rb:96:6:96:9 | foo9 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:96:6:96:19 | call to get_field |
|
||||
| instance_variables.rb:97:6:97:10 | foo10 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:97:6:97:20 | call to get_field |
|
||||
|
||||
@@ -2910,6 +2910,8 @@
|
||||
| local_dataflow.rb:141:19:141:37 | [false] ( ... ) | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... |
|
||||
| local_dataflow.rb:141:19:141:37 | [input] SSA phi read(self) | local_dataflow.rb:141:38:142:9 | [input] SSA phi read(self) |
|
||||
| local_dataflow.rb:141:19:141:37 | [input] SSA phi read(x) | local_dataflow.rb:141:38:142:9 | [input] SSA phi read(x) |
|
||||
| local_dataflow.rb:141:19:141:37 | [post] [false] ( ... ) | local_dataflow.rb:141:20:141:36 | [post] [false] ... && ... |
|
||||
| local_dataflow.rb:141:19:141:37 | [post] [true] ( ... ) | local_dataflow.rb:141:20:141:36 | [post] [true] ... && ... |
|
||||
| local_dataflow.rb:141:19:141:37 | [true] ( ... ) | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... |
|
||||
| local_dataflow.rb:141:20:141:25 | [input] SSA phi read(self) | local_dataflow.rb:143:11:143:16 | self |
|
||||
| local_dataflow.rb:141:20:141:25 | [input] SSA phi read(x) | local_dataflow.rb:143:15:143:15 | x |
|
||||
|
||||
@@ -3405,6 +3405,8 @@
|
||||
| local_dataflow.rb:141:19:141:37 | [false] ( ... ) | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... |
|
||||
| local_dataflow.rb:141:19:141:37 | [input] SSA phi read(self) | local_dataflow.rb:141:38:142:9 | [input] SSA phi read(self) |
|
||||
| local_dataflow.rb:141:19:141:37 | [input] SSA phi read(x) | local_dataflow.rb:141:38:142:9 | [input] SSA phi read(x) |
|
||||
| local_dataflow.rb:141:19:141:37 | [post] [false] ( ... ) | local_dataflow.rb:141:20:141:36 | [post] [false] ... && ... |
|
||||
| local_dataflow.rb:141:19:141:37 | [post] [true] ( ... ) | local_dataflow.rb:141:20:141:36 | [post] [true] ... && ... |
|
||||
| local_dataflow.rb:141:19:141:37 | [true] ( ... ) | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... |
|
||||
| local_dataflow.rb:141:20:141:25 | [input] SSA phi read(self) | local_dataflow.rb:143:11:143:16 | self |
|
||||
| local_dataflow.rb:141:20:141:25 | [input] SSA phi read(x) | local_dataflow.rb:143:15:143:15 | x |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| DeadStoreOfLocal.rb:2:5:2:5 | y | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.rb:2:5:2:5 | y | y |
|
||||
@@ -0,0 +1,2 @@
|
||||
query: queries/variables/DeadStoreOfLocal.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,36 @@
|
||||
def test_basic(x)
|
||||
y = x #$ Alert
|
||||
y = x + 2
|
||||
return y
|
||||
end
|
||||
|
||||
def test_retry
|
||||
x = 0
|
||||
begin
|
||||
if x == 0
|
||||
raise "error"
|
||||
end
|
||||
rescue
|
||||
x = 2 # OK - the retry will allow a later read
|
||||
retry
|
||||
end
|
||||
return 42
|
||||
end
|
||||
|
||||
def test_binding
|
||||
x = 4 # OK - the binding collects the value of x
|
||||
return binding
|
||||
end
|
||||
|
||||
class Sup
|
||||
def m(x)
|
||||
print(x + 1)
|
||||
end
|
||||
end
|
||||
|
||||
class Sub < Sup
|
||||
def m(y)
|
||||
y = 3 # OK - the call to `super` sees the value of `y``
|
||||
super
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
require 'erb'
|
||||
|
||||
template = ERB.new <<EOF
|
||||
<%#-*- coding: Big5 -*-%>
|
||||
\_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
|
||||
x is <%= x %>.
|
||||
EOF
|
||||
x = 5 # OK - the template can see the value of x
|
||||
puts template.result
|
||||
@@ -0,0 +1,4 @@
|
||||
| UninitializedLocal.rb:12:3:12:3 | m | Local variable $@ may be used before it is initialized. | UninitializedLocal.rb:8:7:8:7 | m | m |
|
||||
| UninitializedLocal.rb:34:5:34:5 | b | Local variable $@ may be used before it is initialized. | UninitializedLocal.rb:27:9:27:9 | b | b |
|
||||
| UninitializedLocal.rb:34:23:34:23 | b | Local variable $@ may be used before it is initialized. | UninitializedLocal.rb:27:9:27:9 | b | b |
|
||||
| UninitializedLocal.rb:76:5:76:5 | i | Local variable $@ may be used before it is initialized. | UninitializedLocal.rb:73:9:73:9 | i | i |
|
||||
@@ -0,0 +1,2 @@
|
||||
query: queries/variables/UninitializedLocal.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,77 @@
|
||||
def m
|
||||
puts "m"
|
||||
end
|
||||
|
||||
def foo
|
||||
m # calls m above
|
||||
if false
|
||||
m = "0"
|
||||
m # reads local variable m
|
||||
else
|
||||
end
|
||||
m.strip #$ Alert
|
||||
m2 # undefined local variable or method 'm2' for main (NameError)
|
||||
end
|
||||
|
||||
def test_guards
|
||||
if (a = "3" && a) # OK - a is in a Boolean context
|
||||
a.strip
|
||||
end
|
||||
if (a = "3") && a # OK - a is assigned in the previous conjunct
|
||||
a.strip
|
||||
end
|
||||
if !(a = "3") or a # OK - a is assigned in the previous conjunct
|
||||
a.strip
|
||||
end
|
||||
if false
|
||||
b = "0"
|
||||
end
|
||||
b.nil?
|
||||
b || 0 # OK
|
||||
b&.strip # OK - safe navigation
|
||||
b.strip if b # OK
|
||||
b.close if b && !b.closed # OK
|
||||
b.blowup if b || !b.blownup #$ Alert
|
||||
|
||||
if false
|
||||
c = "0"
|
||||
end
|
||||
unless c
|
||||
return
|
||||
end
|
||||
c.strip # OK - given above unless
|
||||
|
||||
if false
|
||||
d = "0"
|
||||
end
|
||||
if (d.nil?)
|
||||
return
|
||||
end
|
||||
d.strip # OK - given above check
|
||||
|
||||
if false
|
||||
e = "0"
|
||||
end
|
||||
unless (!e.nil?)
|
||||
return
|
||||
end
|
||||
e.strip # OK - given above unless
|
||||
end
|
||||
|
||||
def test_loop
|
||||
begin
|
||||
if false
|
||||
a = 0
|
||||
else
|
||||
set_a
|
||||
end
|
||||
end until a # OK
|
||||
a.strip # OK - given previous until
|
||||
end
|
||||
|
||||
def test_for
|
||||
for i in ["foo", "bar"] # OK - since 0..10 cannot raise
|
||||
puts i.strip
|
||||
end
|
||||
i.strip #$ SPURIOUS: Alert
|
||||
end
|
||||
Reference in New Issue
Block a user