mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Ruby: Data-flow through hashes
This commit is contained in:
@@ -57,6 +57,24 @@ module SummaryComponent {
|
||||
*/
|
||||
SummaryComponent elementAny() { result = SC::content(TAnyElementContent()) }
|
||||
|
||||
/**
|
||||
* Gets a summary component that represents an element in a collection at known
|
||||
* integer index `lower` or above.
|
||||
*/
|
||||
SummaryComponent elementLowerBound(int lower) {
|
||||
result = SC::content(TElementLowerBoundContent(lower))
|
||||
}
|
||||
|
||||
/** Gets a summary component that represents a value in a pair at an unknown key. */
|
||||
SummaryComponent pairValueUnknown() {
|
||||
result = SC::content(TSingletonContent(TUnknownPairValueContent()))
|
||||
}
|
||||
|
||||
/** Gets a summary component that represents a value in a pair at a known key. */
|
||||
SummaryComponent pairValueKnown(ConstantValue cv) {
|
||||
result = SC::content(TSingletonContent(TKnownPairValueContent(cv)))
|
||||
}
|
||||
|
||||
/** Gets a summary component that represents the return value of a call. */
|
||||
SummaryComponent return() { result = SC::return(any(NormalReturnKind rk)) }
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ private import DataFlowPublic
|
||||
private import DataFlowDispatch
|
||||
private import SsaImpl as SsaImpl
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() }
|
||||
@@ -177,7 +178,7 @@ private class Argument extends CfgNodes::ExprCfgNode {
|
||||
exists(int i |
|
||||
this = call.getArgument(i) and
|
||||
not this.getExpr() instanceof BlockArgument and
|
||||
not exists(this.getExpr().(Pair).getKey().getConstantValue().getSymbol()) and
|
||||
not this.getExpr().(Pair).getKey().getConstantValue().isSymbol(_) and
|
||||
arg.isPositional(i)
|
||||
)
|
||||
or
|
||||
@@ -334,7 +335,10 @@ private module Cached {
|
||||
cached
|
||||
newtype TContentSet =
|
||||
TSingletonContent(Content c) or
|
||||
TAnyElementContent()
|
||||
TAnyElementContent() or
|
||||
TElementLowerBoundContent(int lower) {
|
||||
FlowSummaryImplSpecific::ParsePositions::isParsedElementLowerBoundPosition(_, lower)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TContent =
|
||||
@@ -342,8 +346,10 @@ private module Cached {
|
||||
not cv.isInt(_) or
|
||||
cv.getInt() in [0 .. 10]
|
||||
} or
|
||||
TFieldContent(string name) { name = any(InstanceVariable v).getName() } or
|
||||
TUnknownElementContent()
|
||||
TUnknownElementContent() or
|
||||
TKnownPairValueContent(ConstantValue cv) or
|
||||
TUnknownPairValueContent() or
|
||||
TFieldContent(string name) { name = any(InstanceVariable v).getName() }
|
||||
|
||||
/**
|
||||
* Holds if `e` is an `ExprNode` that may be returned by a call to `c`.
|
||||
@@ -362,6 +368,8 @@ private module Cached {
|
||||
|
||||
class TElementContent = TKnownElementContent or TUnknownElementContent;
|
||||
|
||||
class TPairValueContent = TKnownPairValueContent or TUnknownPairValueContent;
|
||||
|
||||
import Cached
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
@@ -818,6 +826,25 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
).getReceiver()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2)
|
||||
or
|
||||
// Needed for pairs passed into method calls where the key is not a symbol,
|
||||
// that is, where it is not a keyword argument.
|
||||
node2.asExpr() =
|
||||
any(CfgNodes::ExprNodes::PairCfgNode pair |
|
||||
exists(CfgNodes::ExprCfgNode key |
|
||||
key = pair.getKey() and
|
||||
pair.getValue() = node1.asExpr()
|
||||
|
|
||||
exists(ConstantValue cv |
|
||||
cv = key.getConstantValue() and
|
||||
not cv.isSymbol(_) and // handled as a keyword argument
|
||||
c.isSingleton(TKnownPairValueContent(cv))
|
||||
)
|
||||
or
|
||||
not exists(key.getConstantValue()) and
|
||||
c.isSingleton(TUnknownPairValueContent())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -242,6 +242,35 @@ module Content {
|
||||
not exists(TKnownElementContent(cv)) and
|
||||
result = TUnknownElementContent()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constant value of `e`, which corresponds to a valid known
|
||||
* element index. Unlike calling simply `e.getConstantValue()`, this
|
||||
* excludes negative array indices.
|
||||
*/
|
||||
ConstantValue getKnownElementIndex(Expr e) {
|
||||
result = getElementContent(e.getConstantValue()).(KnownElementContent).getIndex()
|
||||
}
|
||||
|
||||
/** A value in a pair with a known or unknown key. */
|
||||
class PairValueContent extends Content, TPairValueContent { }
|
||||
|
||||
/** A value in a pair with a known key. */
|
||||
class KnownPairValueContent extends PairValueContent, TKnownPairValueContent {
|
||||
private ConstantValue cv;
|
||||
|
||||
KnownPairValueContent() { this = TKnownPairValueContent(cv) }
|
||||
|
||||
/** Gets the index in the collection. */
|
||||
ConstantValue getIndex() { result = cv }
|
||||
|
||||
override string toString() { result = "pair " + cv }
|
||||
}
|
||||
|
||||
/** A value in a pair with an unknown key. */
|
||||
class UnknownPairValueContent extends PairValueContent, TUnknownPairValueContent {
|
||||
override string toString() { result = "pair" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,6 +286,12 @@ class ContentSet extends TContentSet {
|
||||
/** Holds if this content set represents all `ElementContent`s. */
|
||||
predicate isAnyElement() { this = TAnyElementContent() }
|
||||
|
||||
/**
|
||||
* Holds if this content set represents all `KnownElementContent`s where
|
||||
* the index is an integer greater than or equal to `lower`.
|
||||
*/
|
||||
predicate isElementLowerBound(int lower) { this = TElementLowerBoundContent(lower) }
|
||||
|
||||
/** Gets a textual representation of this content set. */
|
||||
string toString() {
|
||||
exists(Content c |
|
||||
@@ -265,7 +300,12 @@ class ContentSet extends TContentSet {
|
||||
)
|
||||
or
|
||||
this.isAnyElement() and
|
||||
result = "any array element"
|
||||
result = "any element"
|
||||
or
|
||||
exists(int lower |
|
||||
this.isElementLowerBound(lower) and
|
||||
result = lower + ".."
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
@@ -274,6 +314,9 @@ class ContentSet extends TContentSet {
|
||||
or
|
||||
this.isAnyElement() and
|
||||
result = TUnknownElementContent()
|
||||
or
|
||||
this.isElementLowerBound(_) and
|
||||
result = TUnknownElementContent()
|
||||
}
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
@@ -282,6 +325,12 @@ class ContentSet extends TContentSet {
|
||||
or
|
||||
this.isAnyElement() and
|
||||
result instanceof Content::ElementContent
|
||||
or
|
||||
exists(int lower, int i |
|
||||
this.isElementLowerBound(lower) and
|
||||
result.(Content::KnownElementContent).getIndex().isInt(i) and
|
||||
i >= lower
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,11 @@ private SummaryComponent interpretElementArg(string arg) {
|
||||
arg = "any" and
|
||||
result = FlowSummary::SummaryComponent::elementAny()
|
||||
or
|
||||
exists(int lower |
|
||||
ParsePositions::isParsedElementLowerBoundPosition(arg, lower) and
|
||||
result = FlowSummary::SummaryComponent::elementLowerBound(lower)
|
||||
)
|
||||
or
|
||||
exists(ConstantValue cv | result = FlowSummary::SummaryComponent::elementKnown(cv) |
|
||||
cv.isInt(AccessPath::parseInt(arg))
|
||||
or
|
||||
@@ -103,6 +108,16 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) {
|
||||
interpretElementArg(c.getAnArgument("WithoutElement")) and
|
||||
result = FlowSummary::SummaryComponent::withoutContent(cs)
|
||||
)
|
||||
or
|
||||
exists(string arg | arg = c.getAnArgument("PairValue") |
|
||||
arg = "?" and
|
||||
result = FlowSummary::SummaryComponent::pairValueUnknown()
|
||||
or
|
||||
exists(ConstantValue cv |
|
||||
result = FlowSummary::SummaryComponent::pairValueKnown(cv) and
|
||||
cv.serialize() = arg
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a summary component in the format used for flow summaries. */
|
||||
@@ -217,6 +232,13 @@ module ParsePositions {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isElementBody(string body) {
|
||||
exists(AccessPathToken tok |
|
||||
tok.getName() = "Element" and
|
||||
body = tok.getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isParsedParameterPosition(string c, int i) {
|
||||
isParamBody(c) and
|
||||
i = AccessPath::parseInt(c)
|
||||
@@ -241,6 +263,11 @@ module ParsePositions {
|
||||
isArgBody(c) and
|
||||
c = paramName + ":"
|
||||
}
|
||||
|
||||
predicate isParsedElementLowerBoundPosition(string c, int lower) {
|
||||
isElementBody(c) and
|
||||
lower = AccessPath::parseLowerBound(c)
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
|
||||
|
||||
@@ -10,6 +10,7 @@ import core.Object::Object
|
||||
import core.Kernel::Kernel
|
||||
import core.Module
|
||||
import core.Array
|
||||
import core.Hash
|
||||
import core.String
|
||||
import core.Regexp
|
||||
import core.IO
|
||||
|
||||
@@ -6,10 +6,17 @@ private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
|
||||
/** An array index that may be tracked precisely in data flow. */
|
||||
private class ArrayIndex extends int {
|
||||
ArrayIndex() { this = any(DataFlow::Content::KnownElementContent c).getIndex().getInt() }
|
||||
}
|
||||
|
||||
private string lastBlockParam(MethodCall mc, string name, int lastBlockParam) {
|
||||
mc.getMethodName() = name and
|
||||
result = name + "(" + lastBlockParam + ")" and
|
||||
lastBlockParam = mc.getBlock().getNumberOfParameters() - 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides flow summaries for the `Array` class.
|
||||
*
|
||||
@@ -19,23 +26,9 @@ private class ArrayIndex extends int {
|
||||
* module instead.
|
||||
*/
|
||||
module Array {
|
||||
/**
|
||||
* Gets the constant value of `arg`, which corresponds to a valid known
|
||||
* element index. Unlike calling simply `arg.getConstantValue()`, this
|
||||
* excludes negative array indices.
|
||||
*/
|
||||
bindingset[arg]
|
||||
private ConstantValue getKnownElementIndex(Expr arg) {
|
||||
result =
|
||||
DataFlow::Content::getElementContent(arg.getConstantValue())
|
||||
.(DataFlow::Content::KnownElementContent)
|
||||
.getIndex()
|
||||
}
|
||||
|
||||
bindingset[arg]
|
||||
private predicate isUnknownElementIndex(Expr arg) {
|
||||
not exists(getKnownElementIndex(arg)) and
|
||||
not arg instanceof RangeLiteral
|
||||
private predicate isUnknownElementIndex(Expr e) {
|
||||
not exists(DataFlow::Content::getKnownElementIndex(e)) and
|
||||
not e instanceof RangeLiteral
|
||||
}
|
||||
|
||||
private class ArrayLiteralSummary extends SummarizedCallable {
|
||||
@@ -195,11 +188,12 @@ module Array {
|
||||
ElementReferenceReadKnownSummary() {
|
||||
this = methodName + "(" + cv.serialize() + ")" and
|
||||
mc.getNumberOfArguments() = 1 and
|
||||
cv = getKnownElementIndex(mc.getArgument(0))
|
||||
cv = DataFlow::Content::getKnownElementIndex(mc.getArgument(0)) and
|
||||
if methodName = "slice" then cv.isInt(_) else any()
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[" + [cv.serialize(), "?"] + "]" and
|
||||
input = "Argument[self].Element[?," + cv.serialize() + "]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
@@ -230,7 +224,7 @@ module Array {
|
||||
|
||||
ElementReferenceRangeReadKnownSummary() {
|
||||
mc.getNumberOfArguments() = 2 and
|
||||
start = getKnownElementIndex(mc.getArgument(0)).getInt() and
|
||||
start = DataFlow::Content::getKnownElementIndex(mc.getArgument(0)).getInt() and
|
||||
exists(int length | mc.getArgument(1).getConstantValue().isInt(length) |
|
||||
end = (start + length - 1) and
|
||||
this = "[](" + start + ", " + length + ")"
|
||||
@@ -260,8 +254,8 @@ module Array {
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
(
|
||||
input = "Argument[self].Element[?]" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
input = "Argument[self].WithElement[?]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
exists(ArrayIndex i | i >= start and i <= end |
|
||||
input = "Argument[self].Element[" + i + "]" and
|
||||
@@ -281,8 +275,8 @@ module Array {
|
||||
(
|
||||
mc.getNumberOfArguments() = 2 and
|
||||
(
|
||||
not mc.getArgument(0).getConstantValue().isInt(_) or
|
||||
not mc.getArgument(1).getConstantValue().isInt(_)
|
||||
not exists(mc.getArgument(0).getConstantValue()) or
|
||||
not exists(mc.getArgument(1).getConstantValue())
|
||||
)
|
||||
or
|
||||
mc.getNumberOfArguments() = 1 and
|
||||
@@ -296,7 +290,7 @@ module Array {
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
input = "Argument[self].Element[?,0..]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
}
|
||||
@@ -318,7 +312,7 @@ module Array {
|
||||
|
||||
ElementReferenceStoreKnownSummary() {
|
||||
mc.getNumberOfArguments() = 2 and
|
||||
cv = getKnownElementIndex(mc.getArgument(0)) and
|
||||
cv = DataFlow::Content::getKnownElementIndex(mc.getArgument(0)) and
|
||||
this = "[" + cv.serialize() + "]="
|
||||
}
|
||||
|
||||
@@ -382,8 +376,8 @@ module Array {
|
||||
AssocSummary() { this = ["assoc", "rassoc"] }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any].Element[any]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
input = "Argument[self].Element[any].WithElement[any]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -403,11 +397,11 @@ module Array {
|
||||
AtKnownSummary() {
|
||||
this = "at(" + cv.serialize() + "]" and
|
||||
mc.getNumberOfArguments() = 1 and
|
||||
cv = getKnownElementIndex(mc.getArgument(0))
|
||||
cv = DataFlow::Content::getKnownElementIndex(mc.getArgument(0))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[" + [cv.serialize(), "?"] + "]" and
|
||||
input = "Argument[self].Element[" + cv.serialize() + ",?]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
@@ -490,7 +484,7 @@ module Array {
|
||||
CompactBangSummary() { this = "compact!" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
input = "Argument[self].Element[?,0..]" and
|
||||
output = ["ReturnValue.Element[?]", "Argument[self].Element[?]"] and
|
||||
preservesValue = true
|
||||
}
|
||||
@@ -519,19 +513,82 @@ module Array {
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteSummary extends SimpleSummarizedCallable {
|
||||
DeleteSummary() { this = "delete" }
|
||||
abstract private class DeleteSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
DeleteSummary() { mc.getMethodName() = "delete" }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = ["Argument[self].Element[?]", "ReturnValue"]
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]"
|
||||
or
|
||||
input = "Argument[self].WithElement[?]" and
|
||||
output = "Argument[self]"
|
||||
or
|
||||
input = "Argument[block].ReturnValue" and
|
||||
output = "ReturnValue"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteKnownSummary extends DeleteSummary {
|
||||
private ConstantValue cv;
|
||||
|
||||
DeleteKnownSummary() {
|
||||
this = "delete(" + cv.serialize() + ")" and
|
||||
mc.getArgument(0).getConstantValue() = cv
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
(
|
||||
(
|
||||
if cv.isInt(_)
|
||||
then
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].WithoutElement[" + cv.serialize() + "].Element[0..]" and
|
||||
output = "Argument[self].Element[?]"
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..]" and
|
||||
output = "Argument[self]"
|
||||
else (
|
||||
input = "Argument[self].WithoutElement[" + cv.serialize() + "]" and
|
||||
output = "Argument[self]"
|
||||
)
|
||||
)
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
input = "Argument[self].Element[" + cv.serialize() + ",?]" and
|
||||
output = "ReturnValue"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteUnknownSummary extends DeleteSummary {
|
||||
DeleteUnknownSummary() {
|
||||
this = "delete" and
|
||||
not exists(DataFlow::Content::getKnownElementIndex(mc.getArgument(0)))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
(
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = "Argument[self].Element[?]"
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = "Argument[self]"
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "ReturnValue"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
@@ -603,17 +660,26 @@ module Array {
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteIfSummary extends SimpleSummarizedCallable {
|
||||
DeleteIfSummary() { this = "delete_if" }
|
||||
private class DeleteIfSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
DeleteIfSummary() { this = lastBlockParam(mc, "delete_if", lastBlockParam) }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output =
|
||||
["Argument[block].Parameter[0]", "ReturnValue.Element[?]", "Argument[self].Element[?]"] and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]" and
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
or
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = ["ReturnValue.Element[?]", "Argument[self].Element[?]"]
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = ["ReturnValue", "Argument[self]"]
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -631,9 +697,9 @@ module Array {
|
||||
private string getDigArg(MethodCall dig, int i) {
|
||||
dig.getMethodName() = "dig" and
|
||||
exists(Expr arg | arg = dig.getArgument(i) |
|
||||
result = getKnownElementIndex(arg).(ConstantValue::ConstantIntegerValue).serialize()
|
||||
result = DataFlow::Content::getKnownElementIndex(arg).serialize()
|
||||
or
|
||||
not getKnownElementIndex(arg).isInt(_) and
|
||||
not exists(DataFlow::Content::getKnownElementIndex(arg)) and
|
||||
result = "?"
|
||||
)
|
||||
}
|
||||
@@ -647,7 +713,7 @@ module Array {
|
||||
private string buildDigInputSpecComponent(RelevantDigMethodCall dig, int i) {
|
||||
exists(string s |
|
||||
s = getDigArg(dig, i) and
|
||||
if s = "?" then result = "any" else result = [s, "?"]
|
||||
if s = "?" then result = "any" else result = s + ",?"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,14 +749,24 @@ module Array {
|
||||
}
|
||||
}
|
||||
|
||||
private class EachSummary extends SimpleSummarizedCallable {
|
||||
// `each` and `reverse_each` are the same in terms of flow inputs/outputs.
|
||||
EachSummary() { this = ["each", "reverse_each"] }
|
||||
private class EachSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
EachSummary() {
|
||||
exists(string name |
|
||||
// `each` and `reverse_each` are the same in terms of flow inputs/outputs.
|
||||
name = ["each", "reverse_each"] and
|
||||
this = lastBlockParam(mc, name, lastBlockParam)
|
||||
)
|
||||
}
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[0]"
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
or
|
||||
input = "Argument[self].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
@@ -700,7 +776,7 @@ module Array {
|
||||
}
|
||||
|
||||
private class EachIndexSummary extends SimpleSummarizedCallable {
|
||||
EachIndexSummary() { this = "each_index" }
|
||||
EachIndexSummary() { this = ["each_index", "each_key"] }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].WithElement[any]" and
|
||||
@@ -719,17 +795,17 @@ module Array {
|
||||
}
|
||||
|
||||
private class FetchKnownSummary extends FetchSummary {
|
||||
int i;
|
||||
ConstantValue cv;
|
||||
|
||||
FetchKnownSummary() {
|
||||
this = "fetch(" + i + ")" and
|
||||
mc.getArgument(0).getConstantValue().isInt(i) and
|
||||
i >= 0
|
||||
this = "fetch(" + cv.serialize() + ")" and
|
||||
cv = mc.getArgument(0).getConstantValue() and
|
||||
not cv.isInt(any(int i | i < 0))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[?," + i + "]" and
|
||||
input = "Argument[self].Element[?," + cv.serialize() + "]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
input = "Argument[0]" and
|
||||
@@ -745,7 +821,9 @@ module Array {
|
||||
private class FetchUnknownSummary extends FetchSummary {
|
||||
FetchUnknownSummary() {
|
||||
this = "fetch(index)" and
|
||||
not exists(int i | mc.getArgument(0).getConstantValue().isInt(i) and i >= 0)
|
||||
not exists(ConstantValue cv |
|
||||
cv = mc.getArgument(0).getConstantValue() and not cv.isInt(any(int i | i < 0))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
@@ -936,17 +1014,29 @@ module Array {
|
||||
override MethodCall getACall() { result = mc }
|
||||
}
|
||||
|
||||
private class KeepIfSummary extends SimpleSummarizedCallable {
|
||||
KeepIfSummary() { this = "keep_if" }
|
||||
private class KeepIfSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
KeepIfSummary() { this = lastBlockParam(mc, "keep_if", lastBlockParam) }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output =
|
||||
["ReturnValue.Element[?]", "Argument[self].Element[?]", "Argument[block].Parameter[0]"] and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]" and
|
||||
(
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]"
|
||||
or
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = ["ReturnValue.Element[?]", "Argument[self].Element[?]"]
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = ["ReturnValue", "Argument[self]"]
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -1107,17 +1197,26 @@ module Array {
|
||||
}
|
||||
}
|
||||
|
||||
private class RejectBangSummary extends SimpleSummarizedCallable {
|
||||
RejectBangSummary() { this = "reject!" }
|
||||
private class RejectBangSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
RejectBangSummary() { this = lastBlockParam(mc, "reject!", lastBlockParam) }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output =
|
||||
["ReturnValue.Element[?]", "Argument[self].Element[?]", "Argument[block].Parameter[0]"] and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]" and
|
||||
(
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = ["ReturnValue.Element[?]", "Argument[self].Element[?]"]
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = ["ReturnValue", "Argument[self]"]
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -1169,7 +1268,7 @@ module Array {
|
||||
private int c;
|
||||
|
||||
RotateKnownSummary() {
|
||||
getKnownElementIndex(mc.getArgument(0)).isInt(c) and
|
||||
DataFlow::Content::getKnownElementIndex(mc.getArgument(0)).isInt(c) and
|
||||
this = "rotate(" + c + ")"
|
||||
or
|
||||
not exists(mc.getArgument(0)) and c = 1 and this = "rotate"
|
||||
@@ -1197,7 +1296,7 @@ module Array {
|
||||
RotateUnknownSummary() {
|
||||
this = "rotate(index)" and
|
||||
exists(mc.getArgument(0)) and
|
||||
not getKnownElementIndex(mc.getArgument(0)).isInt(_)
|
||||
not DataFlow::Content::getKnownElementIndex(mc.getArgument(0)).isInt(_)
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
@@ -1267,18 +1366,34 @@ module Array {
|
||||
}
|
||||
}
|
||||
|
||||
private class SelectBangSummary extends SimpleSummarizedCallable {
|
||||
// `filter!` is an alias for `select!`
|
||||
SelectBangSummary() { this = ["select!", "filter!"] }
|
||||
private class SelectBangSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
SelectBangSummary() {
|
||||
exists(string name |
|
||||
name = ["select!", "filter!"] and
|
||||
this = lastBlockParam(mc, name, lastBlockParam)
|
||||
)
|
||||
}
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output =
|
||||
["Argument[block].Parameter[0]", "Argument[self].Element[?]", "ReturnValue.Element[?]"] and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]" and
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
or
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = ["ReturnValue.Element[?]", "Argument[self].Element[?]"]
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = ["ReturnValue", "Argument[self]"]
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -1306,8 +1421,18 @@ module Array {
|
||||
or
|
||||
preservesValue = true and
|
||||
(
|
||||
input = "Argument[self].WithoutElement[0..]" and
|
||||
output = "Argument[self]"
|
||||
or
|
||||
input = "Argument[self].Element[?]" and
|
||||
output = ["ReturnValue", "Argument[self].Element[?]"]
|
||||
output =
|
||||
[
|
||||
"ReturnValue", // array
|
||||
"ReturnValue.Element[1]" // hash
|
||||
]
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithoutElement[?].Element[any]" and
|
||||
output = "ReturnValue.Element[1]"
|
||||
or
|
||||
exists(ArrayIndex i | input = "Argument[self].Element[" + i + "]" |
|
||||
i = 0 and output = "ReturnValue"
|
||||
@@ -1403,7 +1528,7 @@ module Array {
|
||||
SliceBangKnownIndexSummary() {
|
||||
this = "slice!(" + n + ")" and
|
||||
mc.getNumberOfArguments() = 1 and
|
||||
n = getKnownElementIndex(mc.getArgument(0)).getInt()
|
||||
n = DataFlow::Content::getKnownElementIndex(mc.getArgument(0)).getInt()
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
@@ -1461,7 +1586,7 @@ module Array {
|
||||
|
||||
SliceBangRangeKnownSummary() {
|
||||
mc.getNumberOfArguments() = 2 and
|
||||
start = getKnownElementIndex(mc.getArgument(0)).getInt() and
|
||||
start = DataFlow::Content::getKnownElementIndex(mc.getArgument(0)).getInt() and
|
||||
exists(int length | mc.getArgument(1).getConstantValue().isInt(length) |
|
||||
end = (start + length - 1) and
|
||||
this = "slice!(" + start + ", " + length + ")"
|
||||
@@ -1633,47 +1758,43 @@ module Array {
|
||||
override Call getACall() { result = mc }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `values_at` where all the arguments are known, positive integers.
|
||||
*/
|
||||
private string getValuesAtComponent(MethodCall mc, int i) {
|
||||
mc.getMethodName() = "values_at" and
|
||||
result = DataFlow::Content::getKnownElementIndex(mc.getArgument(i)).serialize()
|
||||
}
|
||||
|
||||
private class ValuesAtKnownSummary extends ValuesAtSummary {
|
||||
ValuesAtKnownSummary() {
|
||||
this = "values_at(known)" and
|
||||
forall(int i | i in [0 .. mc.getNumberOfArguments() - 1] |
|
||||
getKnownElementIndex(mc.getArgument(i)).isInt(_)
|
||||
)
|
||||
this =
|
||||
"values_at(" +
|
||||
strictconcat(int i |
|
||||
exists(mc.getArgument(i))
|
||||
|
|
||||
getValuesAtComponent(mc, i), "," order by i
|
||||
) + ")"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
(
|
||||
input = "Argument[self].Element[?]" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
or
|
||||
exists(ArrayIndex elementIndex, int argIndex |
|
||||
argIndex in [0 .. mc.getNumberOfArguments() - 1] and
|
||||
getKnownElementIndex(mc.getArgument(argIndex)).isInt(elementIndex)
|
||||
|
|
||||
input = "Argument[self].Element[" + elementIndex + "]" and
|
||||
output = "ReturnValue.Element[" + argIndex + "]"
|
||||
)
|
||||
)
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
exists(string s, int i |
|
||||
s = getValuesAtComponent(mc, i) and
|
||||
input = "Argument[self].Element[" + s + "]" and
|
||||
output = "ReturnValue.Element[" + i + "]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `values_at` where at least one of the arguments is not a known,
|
||||
* positive integer.
|
||||
*/
|
||||
private class ValuesAtUnknownSummary extends ValuesAtSummary {
|
||||
ValuesAtUnknownSummary() {
|
||||
this = "values_at(unknown)" and
|
||||
exists(int i | i in [0 .. mc.getNumberOfArguments() - 1] |
|
||||
not getKnownElementIndex(mc.getArgument(i)).isInt(_)
|
||||
)
|
||||
exists(int i | exists(mc.getArgument(i)) | not exists(getValuesAtComponent(mc, i))) and
|
||||
this = "values_at(?)"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
@@ -1742,9 +1863,16 @@ module Enumerable {
|
||||
CompactSummary() { this = "compact" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
input = "Argument[self].Element[?,0..]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
or
|
||||
exists(ConstantValue cv |
|
||||
not cv.isInt(_) and
|
||||
input = "Argument[self].WithElement[" + cv.serialize() + "]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2254,33 +2382,75 @@ module Enumerable {
|
||||
}
|
||||
}
|
||||
|
||||
private class QuerySummary extends SimpleSummarizedCallable {
|
||||
QuerySummary() { this = ["all?", "any?", "none?", "one?"] }
|
||||
private class QuerySummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
QuerySummary() {
|
||||
exists(string name |
|
||||
name = ["all?", "any?", "none?", "one?"] and
|
||||
this = lastBlockParam(mc, name, lastBlockParam)
|
||||
)
|
||||
}
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[0]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class RejectSummary extends SimpleSummarizedCallable {
|
||||
RejectSummary() { this = "reject" }
|
||||
private class RejectSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
RejectSummary() { this = lastBlockParam(mc, "reject", lastBlockParam) }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = ["Argument[block].Parameter[0]", "ReturnValue.Element[?]"] and
|
||||
(
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SelectSummary extends SimpleSummarizedCallable {
|
||||
// `find_all` and `filter` are aliases of `select`.
|
||||
SelectSummary() { this = ["select", "find_all", "filter"] }
|
||||
private class SelectSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
int lastBlockParam;
|
||||
|
||||
SelectSummary() {
|
||||
exists(string name |
|
||||
name = ["select", "find_all", "filter"] and
|
||||
this = lastBlockParam(mc, name, lastBlockParam)
|
||||
)
|
||||
}
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = ["Argument[block].Parameter[0]", "ReturnValue.Element[?]"] and
|
||||
(
|
||||
// array indices may get shifted
|
||||
input = "Argument[self].Element[0..]" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
or
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[" + lastBlockParam + "]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -2406,7 +2576,7 @@ module Enumerable {
|
||||
ToASummary() { this = ["to_a", "entries", "to_ary"] }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self]" and
|
||||
input = "Argument[self].WithElement[?,0..]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
|
||||
533
ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll
Normal file
533
ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll
Normal file
@@ -0,0 +1,533 @@
|
||||
/** Provides flow summaries for the `Hash` class. */
|
||||
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
|
||||
/**
|
||||
* Provides flow summaries for the `Hash` class.
|
||||
*
|
||||
* The summaries are ordered (and implemented) based on
|
||||
* https://docs.ruby-lang.org/en/3.1/Hash.html.
|
||||
*
|
||||
* Some summaries are shared with the `Array` class, and those are defined
|
||||
* in `Array.qll`.
|
||||
*/
|
||||
module Hash {
|
||||
// cannot use API graphs due to negative recursion
|
||||
private predicate isHashLiteralPair(Pair pair, ConstantValue cv) {
|
||||
cv = DataFlow::Content::getKnownElementIndex(pair.getKey()) and
|
||||
pair = any(MethodCall mc | mc.getMethodName() = "[]").getAnArgument()
|
||||
}
|
||||
|
||||
private class HashLiteralSymbolSummary extends SummarizedCallable {
|
||||
private ConstantValue::ConstantSymbolValue symbol;
|
||||
|
||||
HashLiteralSymbolSummary() {
|
||||
isHashLiteralPair(_, symbol) and
|
||||
this = "Hash.[:" + symbol.serialize() + "]"
|
||||
}
|
||||
|
||||
final override MethodCall getACall() {
|
||||
result = API::getTopLevelMember("Hash").getAMethodCall("[]").getExprNode().getExpr() and
|
||||
exists(result.getKeywordArgument(symbol.getSymbol()))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
// { symbol: x }
|
||||
input = "Argument[" + symbol.getSymbol() + ":]" and
|
||||
output = "ReturnValue.Element[" + symbol.serialize() + "]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class HashLiteralNonSymbolSummary extends SummarizedCallable {
|
||||
private ConstantValue cv;
|
||||
|
||||
HashLiteralNonSymbolSummary() {
|
||||
this = "Hash.[]" and
|
||||
isHashLiteralPair(_, cv) and
|
||||
not cv.isSymbol(_)
|
||||
}
|
||||
|
||||
final override MethodCall getACall() {
|
||||
result = API::getTopLevelMember("Hash").getAMethodCall("[]").getExprNode().getExpr() and
|
||||
isHashLiteralPair(result.getAnArgument(), cv)
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
// { 'nonsymbol' => x }
|
||||
input = "Argument[0..].PairValue[" + cv.serialize() + "]" and
|
||||
output = "ReturnValue.Element[" + cv.serialize() + "]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class HashNewSummary extends SummarizedCallable {
|
||||
HashNewSummary() { this = "Hash[]" }
|
||||
|
||||
final override ElementReference getACall() {
|
||||
result.getReceiver() = API::getTopLevelMember("Hash").getAUse().asExpr().getExpr() and
|
||||
result.getNumberOfArguments() = 1
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
// Hash[{symbol: x}]
|
||||
input = "Argument[0].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
// Hash[[:symbol, x]]
|
||||
input = "Argument[0].Element[any].Element[1]" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class HashNewSummary2 extends SummarizedCallable {
|
||||
private int i;
|
||||
private ConstantValue cv;
|
||||
|
||||
HashNewSummary2() {
|
||||
this = "Hash[" + i + ", " + cv.serialize() + "]" and
|
||||
i % 2 = 1 and
|
||||
exists(ElementReference er |
|
||||
cv = er.getArgument(i - 1).getConstantValue() and
|
||||
exists(er.getArgument(i))
|
||||
)
|
||||
}
|
||||
|
||||
final override ElementReference getACall() {
|
||||
result.getReceiver() = API::getTopLevelMember("Hash").getAUse().asExpr().getExpr() and
|
||||
cv = result.getArgument(i - 1).getConstantValue() and
|
||||
exists(result.getArgument(i))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
// Hash[:symbol, x]
|
||||
input = "Argument[" + i + "]" and
|
||||
output = "ReturnValue.Element[" + cv.serialize() + "]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class TryConvertSummary extends SummarizedCallable {
|
||||
TryConvertSummary() { this = "Hash.try_convert" }
|
||||
|
||||
override MethodCall getACall() {
|
||||
result = API::getTopLevelMember("Hash").getAMethodCall("try_convert").getExprNode().getExpr()
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0].WithElement[any]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class StoreSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
StoreSummary() { mc.getMethodName() = "store" and mc.getNumberOfArguments() = 2 }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[1]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class StoreKnownSummary extends StoreSummary {
|
||||
private ConstantValue cv;
|
||||
|
||||
StoreKnownSummary() {
|
||||
cv = DataFlow::Content::getKnownElementIndex(mc.getArgument(0)) and
|
||||
this = "store(" + cv.serialize() + ")"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
input = "Argument[1]" and
|
||||
output = "Argument[self].Element[" + cv.serialize() + "]" and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "Argument[self].WithoutElement[" + cv.serialize() + "]" and
|
||||
output = "Argument[self]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class StoreUnknownSummary extends StoreSummary {
|
||||
StoreUnknownSummary() {
|
||||
not exists(DataFlow::Content::getKnownElementIndex(mc.getArgument(0))) and
|
||||
this = "store"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
input = "Argument[1]" and
|
||||
output = "Argument[self].Element[?]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class AssocSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
AssocSummary() { mc.getMethodName() = "assoc" }
|
||||
|
||||
override MethodCall getACall() { result = mc }
|
||||
}
|
||||
|
||||
private class AssocKnownSummary extends AssocSummary {
|
||||
private ConstantValue cv;
|
||||
|
||||
AssocKnownSummary() {
|
||||
this = "assoc(" + cv.serialize() + "]" and
|
||||
not cv.isInt(_) and // exclude arrays
|
||||
mc.getNumberOfArguments() = 1 and
|
||||
cv = DataFlow::Content::getKnownElementIndex(mc.getArgument(0))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[" + cv.serialize() + ",?]" and
|
||||
output = "ReturnValue.Element[1]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class AssocUnknownSummary extends AssocSummary {
|
||||
AssocUnknownSummary() {
|
||||
this = "assoc" and
|
||||
mc.getNumberOfArguments() = 1 and
|
||||
not exists(DataFlow::Content::getKnownElementIndex(mc.getArgument(0)))
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any].WithoutElement[any]" and
|
||||
output = "ReturnValue.Element[1]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class EachPairSummary extends SimpleSummarizedCallable {
|
||||
EachPairSummary() { this = "each_pair" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[1]"
|
||||
or
|
||||
input = "Argument[self].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class EachValueSummary extends SimpleSummarizedCallable {
|
||||
EachValueSummary() { this = "each_value" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[0]"
|
||||
or
|
||||
input = "Argument[self].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private string getExceptComponent(MethodCall mc, int i) {
|
||||
mc.getMethodName() = "except" and
|
||||
result = DataFlow::Content::getKnownElementIndex(mc.getArgument(i)).serialize()
|
||||
}
|
||||
|
||||
private class ExceptSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
ExceptSummary() {
|
||||
mc.getMethodName() = "except" and
|
||||
this =
|
||||
"except(" + concat(int i, string s | s = getExceptComponent(mc, i) | s, "," order by i) +
|
||||
")"
|
||||
}
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input =
|
||||
"Argument[self]" +
|
||||
concat(int i, string s |
|
||||
s = getExceptComponent(mc, i)
|
||||
|
|
||||
".WithoutElement[" + s + "]" order by i
|
||||
) and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class FetchValuesSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
FetchValuesSummary() { mc.getMethodName() = "fetch_values" }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].WithElement[?]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
input = "Argument[0]" and
|
||||
output = "Argument[block].Parameter[0]"
|
||||
or
|
||||
input = "Argument[block].ReturnValue" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class FetchValuesKnownSummary extends FetchValuesSummary {
|
||||
ConstantValue cv;
|
||||
|
||||
FetchValuesKnownSummary() {
|
||||
forex(Expr arg | arg = mc.getAnArgument() | exists(arg.getConstantValue())) and
|
||||
cv = mc.getAnArgument().getConstantValue() and
|
||||
this = "fetch_values(" + cv.serialize() + ")"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
input = "Argument[self].Element[" + cv.serialize() + "]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class FetchValuesUnknownSummary extends FetchValuesSummary {
|
||||
FetchValuesUnknownSummary() {
|
||||
exists(Expr arg | arg = mc.getAnArgument() | not exists(arg.getConstantValue())) and
|
||||
this = "fetch_values(?)"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
super.propagatesFlowExt(input, output, preservesValue)
|
||||
or
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class MergeSummary extends SimpleSummarizedCallable {
|
||||
MergeSummary() { this = "merge" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[any].WithElement[any]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
input = "Argument[any].Element[any]" and
|
||||
output = "Argument[block].Parameter[1,2]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class MergeBangSummary extends SimpleSummarizedCallable {
|
||||
MergeBangSummary() { this = ["merge!", "update"] }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[any].WithElement[any]" and
|
||||
output = ["ReturnValue", "Argument[self]"]
|
||||
or
|
||||
input = "Argument[any].Element[any]" and
|
||||
output = "Argument[block].Parameter[1,2]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class RassocSummary extends SimpleSummarizedCallable {
|
||||
RassocSummary() { this = "rassoc" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any].WithoutElement[any]" and
|
||||
output = "ReturnValue.Element[1]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class SliceSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
SliceSummary() { mc.getMethodName() = "slice" }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
}
|
||||
|
||||
private class SliceKnownSummary extends SliceSummary {
|
||||
ConstantValue cv;
|
||||
|
||||
SliceKnownSummary() {
|
||||
cv = mc.getAnArgument().getConstantValue() and
|
||||
this = "slice(" + cv.serialize() + ")" and
|
||||
not cv.isInt(_) // covered in `Array.qll`
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].WithElement[?," + cv.serialize() + "]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SliceUnknownSummary extends SliceSummary {
|
||||
SliceUnknownSummary() {
|
||||
exists(Expr arg | arg = mc.getAnArgument() | not exists(arg.getConstantValue())) and
|
||||
this = "slice(?)"
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].WithoutElement[0..].WithElement[any]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class ToASummary extends SimpleSummarizedCallable {
|
||||
ToASummary() { this = "to_a" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].WithoutElement[0..].Element[any]" and
|
||||
output = "ReturnValue.Element[?].Element[1]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class ToHWithoutBlockSummary extends SimpleSummarizedCallable {
|
||||
ToHWithoutBlockSummary() { this = ["to_h", "to_hash"] and not exists(mc.getBlock()) }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].WithElement[any]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class ToHWithBlockSummary extends SimpleSummarizedCallable {
|
||||
ToHWithBlockSummary() { this = "to_h" and exists(mc.getBlock()) }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[1]"
|
||||
or
|
||||
input = "Argument[block].ReturnValue.Element[1]" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class TransformKeysSummary extends SimpleSummarizedCallable {
|
||||
TransformKeysSummary() { this = "transform_keys" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class TransformKeysBangSummary extends SimpleSummarizedCallable {
|
||||
TransformKeysBangSummary() { this = "transform_keys!" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[self].Element[?]"
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class TransformValuesSummary extends SimpleSummarizedCallable {
|
||||
TransformValuesSummary() { this = "transform_values" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[0]"
|
||||
or
|
||||
input = "Argument[block].ReturnValue" and
|
||||
output = "ReturnValue.Element[?]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class TransformValuesBangSummary extends SimpleSummarizedCallable {
|
||||
TransformValuesBangSummary() { this = "transform_values!" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
(
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "Argument[block].Parameter[0]"
|
||||
or
|
||||
input = "Argument[block].ReturnValue" and
|
||||
output = "Argument[self].Element[?]"
|
||||
or
|
||||
input = "Argument[self].WithoutElement[any]" and
|
||||
output = "Argument[self]"
|
||||
) and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class ValuesSummary extends SimpleSummarizedCallable {
|
||||
ValuesSummary() { this = "values" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Element[any]" and
|
||||
output = "ReturnValue.Element[?]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class ValuesAtSummary extends SummarizedCallable {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
ValuesAtSummary() { mc.getMethodName() = "values_at" }
|
||||
|
||||
final override MethodCall getACall() { result = mc }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].WithElement[?]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
@@ -332,16 +332,16 @@ edges
|
||||
| array_flow.rb:178:16:178:16 | c [element 1] : | array_flow.rb:179:11:179:11 | d [element 2, element 1] : |
|
||||
| array_flow.rb:178:16:178:16 | c [element 1] : | array_flow.rb:180:11:180:11 | d [element 2, element 1] : |
|
||||
| array_flow.rb:178:16:178:16 | c [element 1] : | array_flow.rb:180:11:180:11 | d [element 2, element 1] : |
|
||||
| array_flow.rb:179:11:179:11 | d [element 2, element 1] : | array_flow.rb:179:11:179:22 | call to assoc [element] : |
|
||||
| array_flow.rb:179:11:179:11 | d [element 2, element 1] : | array_flow.rb:179:11:179:22 | call to assoc [element] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element] : | array_flow.rb:179:11:179:25 | ...[...] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element] : | array_flow.rb:179:11:179:25 | ...[...] : |
|
||||
| array_flow.rb:179:11:179:11 | d [element 2, element 1] : | array_flow.rb:179:11:179:22 | call to assoc [element 1] : |
|
||||
| array_flow.rb:179:11:179:11 | d [element 2, element 1] : | array_flow.rb:179:11:179:22 | call to assoc [element 1] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element 1] : | array_flow.rb:179:11:179:25 | ...[...] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element 1] : | array_flow.rb:179:11:179:25 | ...[...] : |
|
||||
| array_flow.rb:179:11:179:25 | ...[...] : | array_flow.rb:179:10:179:26 | ( ... ) |
|
||||
| array_flow.rb:179:11:179:25 | ...[...] : | array_flow.rb:179:10:179:26 | ( ... ) |
|
||||
| array_flow.rb:180:11:180:11 | d [element 2, element 1] : | array_flow.rb:180:11:180:22 | call to assoc [element] : |
|
||||
| array_flow.rb:180:11:180:11 | d [element 2, element 1] : | array_flow.rb:180:11:180:22 | call to assoc [element] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element] : | array_flow.rb:180:11:180:25 | ...[...] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element] : | array_flow.rb:180:11:180:25 | ...[...] : |
|
||||
| array_flow.rb:180:11:180:11 | d [element 2, element 1] : | array_flow.rb:180:11:180:22 | call to assoc [element 1] : |
|
||||
| array_flow.rb:180:11:180:11 | d [element 2, element 1] : | array_flow.rb:180:11:180:22 | call to assoc [element 1] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element 1] : | array_flow.rb:180:11:180:25 | ...[...] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element 1] : | array_flow.rb:180:11:180:25 | ...[...] : |
|
||||
| array_flow.rb:180:11:180:25 | ...[...] : | array_flow.rb:180:10:180:26 | ( ... ) |
|
||||
| array_flow.rb:180:11:180:25 | ...[...] : | array_flow.rb:180:10:180:26 | ( ... ) |
|
||||
| array_flow.rb:184:13:184:22 | call to source : | array_flow.rb:186:10:186:10 | a [element 1] : |
|
||||
@@ -520,26 +520,12 @@ edges
|
||||
| array_flow.rb:312:10:312:10 | b [element 2] : | array_flow.rb:312:10:312:13 | ...[...] |
|
||||
| array_flow.rb:316:16:316:27 | call to source : | array_flow.rb:317:9:317:9 | a [element 2] : |
|
||||
| array_flow.rb:316:16:316:27 | call to source : | array_flow.rb:317:9:317:9 | a [element 2] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | array_flow.rb:319:10:319:10 | a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | array_flow.rb:319:10:319:10 | a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | array_flow.rb:320:10:320:10 | a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | array_flow.rb:320:10:320:10 | a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | array_flow.rb:321:10:321:10 | a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | array_flow.rb:321:10:321:10 | a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | a [element 2] : | array_flow.rb:317:9:317:9 | [post] a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | a [element 2] : | array_flow.rb:317:9:317:9 | [post] a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | a [element 2] : | array_flow.rb:317:9:317:36 | call to delete : |
|
||||
| array_flow.rb:317:9:317:9 | a [element 2] : | array_flow.rb:317:9:317:36 | call to delete : |
|
||||
| array_flow.rb:317:9:317:36 | call to delete : | array_flow.rb:318:10:318:10 | b |
|
||||
| array_flow.rb:317:9:317:36 | call to delete : | array_flow.rb:318:10:318:10 | b |
|
||||
| array_flow.rb:317:23:317:34 | call to source : | array_flow.rb:317:9:317:36 | call to delete : |
|
||||
| array_flow.rb:317:23:317:34 | call to source : | array_flow.rb:317:9:317:36 | call to delete : |
|
||||
| array_flow.rb:319:10:319:10 | a [element] : | array_flow.rb:319:10:319:13 | ...[...] |
|
||||
| array_flow.rb:319:10:319:10 | a [element] : | array_flow.rb:319:10:319:13 | ...[...] |
|
||||
| array_flow.rb:320:10:320:10 | a [element] : | array_flow.rb:320:10:320:13 | ...[...] |
|
||||
| array_flow.rb:320:10:320:10 | a [element] : | array_flow.rb:320:10:320:13 | ...[...] |
|
||||
| array_flow.rb:321:10:321:10 | a [element] : | array_flow.rb:321:10:321:13 | ...[...] |
|
||||
| array_flow.rb:321:10:321:10 | a [element] : | array_flow.rb:321:10:321:13 | ...[...] |
|
||||
| array_flow.rb:325:16:325:27 | call to source : | array_flow.rb:326:9:326:9 | a [element 2] : |
|
||||
| array_flow.rb:325:16:325:27 | call to source : | array_flow.rb:326:9:326:9 | a [element 2] : |
|
||||
| array_flow.rb:325:30:325:41 | call to source : | array_flow.rb:326:9:326:9 | a [element 3] : |
|
||||
@@ -578,6 +564,8 @@ edges
|
||||
| array_flow.rb:334:10:334:10 | a [element] : | array_flow.rb:334:10:334:13 | ...[...] |
|
||||
| array_flow.rb:338:16:338:25 | call to source : | array_flow.rb:339:9:339:9 | a [element 2] : |
|
||||
| array_flow.rb:338:16:338:25 | call to source : | array_flow.rb:339:9:339:9 | a [element 2] : |
|
||||
| array_flow.rb:338:16:338:25 | call to source : | array_flow.rb:345:10:345:10 | a [element 2] : |
|
||||
| array_flow.rb:338:16:338:25 | call to source : | array_flow.rb:345:10:345:10 | a [element 2] : |
|
||||
| array_flow.rb:339:9:339:9 | [post] a [element] : | array_flow.rb:343:10:343:10 | a [element] : |
|
||||
| array_flow.rb:339:9:339:9 | [post] a [element] : | array_flow.rb:343:10:343:10 | a [element] : |
|
||||
| array_flow.rb:339:9:339:9 | [post] a [element] : | array_flow.rb:344:10:344:10 | a [element] : |
|
||||
@@ -600,6 +588,8 @@ edges
|
||||
| array_flow.rb:343:10:343:10 | a [element] : | array_flow.rb:343:10:343:13 | ...[...] |
|
||||
| array_flow.rb:344:10:344:10 | a [element] : | array_flow.rb:344:10:344:13 | ...[...] |
|
||||
| array_flow.rb:344:10:344:10 | a [element] : | array_flow.rb:344:10:344:13 | ...[...] |
|
||||
| array_flow.rb:345:10:345:10 | a [element 2] : | array_flow.rb:345:10:345:13 | ...[...] |
|
||||
| array_flow.rb:345:10:345:10 | a [element 2] : | array_flow.rb:345:10:345:13 | ...[...] |
|
||||
| array_flow.rb:345:10:345:10 | a [element] : | array_flow.rb:345:10:345:13 | ...[...] |
|
||||
| array_flow.rb:345:10:345:10 | a [element] : | array_flow.rb:345:10:345:13 | ...[...] |
|
||||
| array_flow.rb:349:16:349:25 | call to source : | array_flow.rb:350:9:350:9 | a [element 2] : |
|
||||
@@ -1703,14 +1693,14 @@ edges
|
||||
| array_flow.rb:945:16:945:16 | c [element 0] : | array_flow.rb:946:10:946:10 | d [element 2, element 0] : |
|
||||
| array_flow.rb:945:16:945:16 | c [element 0] : | array_flow.rb:947:10:947:10 | d [element 2, element 0] : |
|
||||
| array_flow.rb:945:16:945:16 | c [element 0] : | array_flow.rb:947:10:947:10 | d [element 2, element 0] : |
|
||||
| array_flow.rb:946:10:946:10 | d [element 2, element 0] : | array_flow.rb:946:10:946:22 | call to rassoc [element] : |
|
||||
| array_flow.rb:946:10:946:10 | d [element 2, element 0] : | array_flow.rb:946:10:946:22 | call to rassoc [element] : |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element] : | array_flow.rb:946:10:946:25 | ...[...] |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element] : | array_flow.rb:946:10:946:25 | ...[...] |
|
||||
| array_flow.rb:947:10:947:10 | d [element 2, element 0] : | array_flow.rb:947:10:947:22 | call to rassoc [element] : |
|
||||
| array_flow.rb:947:10:947:10 | d [element 2, element 0] : | array_flow.rb:947:10:947:22 | call to rassoc [element] : |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element] : | array_flow.rb:947:10:947:25 | ...[...] |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element] : | array_flow.rb:947:10:947:25 | ...[...] |
|
||||
| array_flow.rb:946:10:946:10 | d [element 2, element 0] : | array_flow.rb:946:10:946:22 | call to rassoc [element 0] : |
|
||||
| array_flow.rb:946:10:946:10 | d [element 2, element 0] : | array_flow.rb:946:10:946:22 | call to rassoc [element 0] : |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element 0] : | array_flow.rb:946:10:946:25 | ...[...] |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element 0] : | array_flow.rb:946:10:946:25 | ...[...] |
|
||||
| array_flow.rb:947:10:947:10 | d [element 2, element 0] : | array_flow.rb:947:10:947:22 | call to rassoc [element 0] : |
|
||||
| array_flow.rb:947:10:947:10 | d [element 2, element 0] : | array_flow.rb:947:10:947:22 | call to rassoc [element 0] : |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element 0] : | array_flow.rb:947:10:947:25 | ...[...] |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element 0] : | array_flow.rb:947:10:947:25 | ...[...] |
|
||||
| array_flow.rb:951:10:951:21 | call to source : | array_flow.rb:952:9:952:9 | a [element 0] : |
|
||||
| array_flow.rb:951:10:951:21 | call to source : | array_flow.rb:952:9:952:9 | a [element 0] : |
|
||||
| array_flow.rb:951:10:951:21 | call to source : | array_flow.rb:957:9:957:9 | a [element 0] : |
|
||||
@@ -3277,8 +3267,12 @@ edges
|
||||
| array_flow.rb:1574:10:1574:10 | b [element] : | array_flow.rb:1574:10:1574:13 | ...[...] |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 1] : | array_flow.rb:1576:9:1576:28 | call to values_at [element] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 1] : | array_flow.rb:1576:9:1576:28 | call to values_at [element] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 3] : | array_flow.rb:1576:9:1576:28 | call to values_at [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 3] : | array_flow.rb:1576:9:1576:28 | call to values_at [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 3] : | array_flow.rb:1576:9:1576:28 | call to values_at [element] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 3] : | array_flow.rb:1576:9:1576:28 | call to values_at [element] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element 1] : | array_flow.rb:1578:10:1578:10 | b [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element 1] : | array_flow.rb:1578:10:1578:10 | b [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element] : | array_flow.rb:1577:10:1577:10 | b [element] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element] : | array_flow.rb:1577:10:1577:10 | b [element] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element] : | array_flow.rb:1578:10:1578:10 | b [element] : |
|
||||
@@ -3289,6 +3283,8 @@ edges
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element] : | array_flow.rb:1580:10:1580:10 | b [element] : |
|
||||
| array_flow.rb:1577:10:1577:10 | b [element] : | array_flow.rb:1577:10:1577:13 | ...[...] |
|
||||
| array_flow.rb:1577:10:1577:10 | b [element] : | array_flow.rb:1577:10:1577:13 | ...[...] |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element 1] : | array_flow.rb:1578:10:1578:13 | ...[...] |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element 1] : | array_flow.rb:1578:10:1578:13 | ...[...] |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element] : | array_flow.rb:1578:10:1578:13 | ...[...] |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element] : | array_flow.rb:1578:10:1578:13 | ...[...] |
|
||||
| array_flow.rb:1579:10:1579:10 | b [element] : | array_flow.rb:1579:10:1579:13 | ...[...] |
|
||||
@@ -3748,16 +3744,16 @@ nodes
|
||||
| array_flow.rb:179:10:179:26 | ( ... ) | semmle.label | ( ... ) |
|
||||
| array_flow.rb:179:11:179:11 | d [element 2, element 1] : | semmle.label | d [element 2, element 1] : |
|
||||
| array_flow.rb:179:11:179:11 | d [element 2, element 1] : | semmle.label | d [element 2, element 1] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element] : | semmle.label | call to assoc [element] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element] : | semmle.label | call to assoc [element] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element 1] : | semmle.label | call to assoc [element 1] : |
|
||||
| array_flow.rb:179:11:179:22 | call to assoc [element 1] : | semmle.label | call to assoc [element 1] : |
|
||||
| array_flow.rb:179:11:179:25 | ...[...] : | semmle.label | ...[...] : |
|
||||
| array_flow.rb:179:11:179:25 | ...[...] : | semmle.label | ...[...] : |
|
||||
| array_flow.rb:180:10:180:26 | ( ... ) | semmle.label | ( ... ) |
|
||||
| array_flow.rb:180:10:180:26 | ( ... ) | semmle.label | ( ... ) |
|
||||
| array_flow.rb:180:11:180:11 | d [element 2, element 1] : | semmle.label | d [element 2, element 1] : |
|
||||
| array_flow.rb:180:11:180:11 | d [element 2, element 1] : | semmle.label | d [element 2, element 1] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element] : | semmle.label | call to assoc [element] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element] : | semmle.label | call to assoc [element] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element 1] : | semmle.label | call to assoc [element 1] : |
|
||||
| array_flow.rb:180:11:180:22 | call to assoc [element 1] : | semmle.label | call to assoc [element 1] : |
|
||||
| array_flow.rb:180:11:180:25 | ...[...] : | semmle.label | ...[...] : |
|
||||
| array_flow.rb:180:11:180:25 | ...[...] : | semmle.label | ...[...] : |
|
||||
| array_flow.rb:184:13:184:22 | call to source : | semmle.label | call to source : |
|
||||
@@ -3970,8 +3966,6 @@ nodes
|
||||
| array_flow.rb:312:10:312:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:316:16:316:27 | call to source : | semmle.label | call to source : |
|
||||
| array_flow.rb:316:16:316:27 | call to source : | semmle.label | call to source : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | semmle.label | [post] a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | [post] a [element] : | semmle.label | [post] a [element] : |
|
||||
| array_flow.rb:317:9:317:9 | a [element 2] : | semmle.label | a [element 2] : |
|
||||
| array_flow.rb:317:9:317:9 | a [element 2] : | semmle.label | a [element 2] : |
|
||||
| array_flow.rb:317:9:317:36 | call to delete : | semmle.label | call to delete : |
|
||||
@@ -3980,18 +3974,6 @@ nodes
|
||||
| array_flow.rb:317:23:317:34 | call to source : | semmle.label | call to source : |
|
||||
| array_flow.rb:318:10:318:10 | b | semmle.label | b |
|
||||
| array_flow.rb:318:10:318:10 | b | semmle.label | b |
|
||||
| array_flow.rb:319:10:319:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:319:10:319:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:319:10:319:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:319:10:319:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:320:10:320:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:320:10:320:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:320:10:320:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:320:10:320:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:321:10:321:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:321:10:321:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:321:10:321:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:321:10:321:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:325:16:325:27 | call to source : | semmle.label | call to source : |
|
||||
| array_flow.rb:325:16:325:27 | call to source : | semmle.label | call to source : |
|
||||
| array_flow.rb:325:30:325:41 | call to source : | semmle.label | call to source : |
|
||||
@@ -4056,6 +4038,8 @@ nodes
|
||||
| array_flow.rb:344:10:344:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:344:10:344:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:344:10:344:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:345:10:345:10 | a [element 2] : | semmle.label | a [element 2] : |
|
||||
| array_flow.rb:345:10:345:10 | a [element 2] : | semmle.label | a [element 2] : |
|
||||
| array_flow.rb:345:10:345:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:345:10:345:10 | a [element] : | semmle.label | a [element] : |
|
||||
| array_flow.rb:345:10:345:13 | ...[...] | semmle.label | ...[...] |
|
||||
@@ -5278,14 +5262,14 @@ nodes
|
||||
| array_flow.rb:945:16:945:16 | c [element 0] : | semmle.label | c [element 0] : |
|
||||
| array_flow.rb:946:10:946:10 | d [element 2, element 0] : | semmle.label | d [element 2, element 0] : |
|
||||
| array_flow.rb:946:10:946:10 | d [element 2, element 0] : | semmle.label | d [element 2, element 0] : |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element] : | semmle.label | call to rassoc [element] : |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element] : | semmle.label | call to rassoc [element] : |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element 0] : | semmle.label | call to rassoc [element 0] : |
|
||||
| array_flow.rb:946:10:946:22 | call to rassoc [element 0] : | semmle.label | call to rassoc [element 0] : |
|
||||
| array_flow.rb:946:10:946:25 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:946:10:946:25 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:947:10:947:10 | d [element 2, element 0] : | semmle.label | d [element 2, element 0] : |
|
||||
| array_flow.rb:947:10:947:10 | d [element 2, element 0] : | semmle.label | d [element 2, element 0] : |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element] : | semmle.label | call to rassoc [element] : |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element] : | semmle.label | call to rassoc [element] : |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element 0] : | semmle.label | call to rassoc [element 0] : |
|
||||
| array_flow.rb:947:10:947:22 | call to rassoc [element 0] : | semmle.label | call to rassoc [element 0] : |
|
||||
| array_flow.rb:947:10:947:25 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:947:10:947:25 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:951:10:951:21 | call to source : | semmle.label | call to source : |
|
||||
@@ -6910,12 +6894,16 @@ nodes
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 1] : | semmle.label | a [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 3] : | semmle.label | a [element 3] : |
|
||||
| array_flow.rb:1576:9:1576:9 | a [element 3] : | semmle.label | a [element 3] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element 1] : | semmle.label | call to values_at [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element 1] : | semmle.label | call to values_at [element 1] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element] : | semmle.label | call to values_at [element] : |
|
||||
| array_flow.rb:1576:9:1576:28 | call to values_at [element] : | semmle.label | call to values_at [element] : |
|
||||
| array_flow.rb:1577:10:1577:10 | b [element] : | semmle.label | b [element] : |
|
||||
| array_flow.rb:1577:10:1577:10 | b [element] : | semmle.label | b [element] : |
|
||||
| array_flow.rb:1577:10:1577:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:1577:10:1577:13 | ...[...] | semmle.label | ...[...] |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element 1] : | semmle.label | b [element 1] : |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element 1] : | semmle.label | b [element 1] : |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element] : | semmle.label | b [element] : |
|
||||
| array_flow.rb:1578:10:1578:10 | b [element] : | semmle.label | b [element] : |
|
||||
| array_flow.rb:1578:10:1578:13 | ...[...] | semmle.label | ...[...] |
|
||||
@@ -7125,9 +7113,6 @@ subpaths
|
||||
| array_flow.rb:312:10:312:13 | ...[...] | array_flow.rb:308:16:308:25 | call to source : | array_flow.rb:312:10:312:13 | ...[...] | $@ | array_flow.rb:308:16:308:25 | call to source : | call to source : |
|
||||
| array_flow.rb:318:10:318:10 | b | array_flow.rb:316:16:316:27 | call to source : | array_flow.rb:318:10:318:10 | b | $@ | array_flow.rb:316:16:316:27 | call to source : | call to source : |
|
||||
| array_flow.rb:318:10:318:10 | b | array_flow.rb:317:23:317:34 | call to source : | array_flow.rb:318:10:318:10 | b | $@ | array_flow.rb:317:23:317:34 | call to source : | call to source : |
|
||||
| array_flow.rb:319:10:319:13 | ...[...] | array_flow.rb:316:16:316:27 | call to source : | array_flow.rb:319:10:319:13 | ...[...] | $@ | array_flow.rb:316:16:316:27 | call to source : | call to source : |
|
||||
| array_flow.rb:320:10:320:13 | ...[...] | array_flow.rb:316:16:316:27 | call to source : | array_flow.rb:320:10:320:13 | ...[...] | $@ | array_flow.rb:316:16:316:27 | call to source : | call to source : |
|
||||
| array_flow.rb:321:10:321:13 | ...[...] | array_flow.rb:316:16:316:27 | call to source : | array_flow.rb:321:10:321:13 | ...[...] | $@ | array_flow.rb:316:16:316:27 | call to source : | call to source : |
|
||||
| array_flow.rb:327:10:327:10 | b | array_flow.rb:325:16:325:27 | call to source : | array_flow.rb:327:10:327:10 | b | $@ | array_flow.rb:325:16:325:27 | call to source : | call to source : |
|
||||
| array_flow.rb:328:10:328:13 | ...[...] | array_flow.rb:325:30:325:41 | call to source : | array_flow.rb:328:10:328:13 | ...[...] | $@ | array_flow.rb:325:30:325:41 | call to source : | call to source : |
|
||||
| array_flow.rb:332:10:332:10 | b | array_flow.rb:330:16:330:27 | call to source : | array_flow.rb:332:10:332:10 | b | $@ | array_flow.rb:330:16:330:27 | call to source : | call to source : |
|
||||
|
||||
@@ -176,8 +176,8 @@ def m19
|
||||
b = ["b", 1]
|
||||
c = ["c", source(19)]
|
||||
d = [a, b, c]
|
||||
sink (d.assoc("a")[0]) # $ hasValueFlow=19
|
||||
sink (d.assoc("c")[0]) # $ hasValueFlow=19
|
||||
sink (d.assoc("a")[1]) # $ hasValueFlow=19
|
||||
sink (d.assoc("c")[1]) # $ hasValueFlow=19
|
||||
end
|
||||
|
||||
def m20(i)
|
||||
@@ -316,9 +316,9 @@ def m36
|
||||
a = [0, 1, source(36.1)]
|
||||
b = a.delete(2) { source(36.2) }
|
||||
sink b # $ hasValueFlow=36.1 $ hasValueFlow=36.2
|
||||
sink a[0] # $ hasValueFlow=36.1
|
||||
sink a[1] # $ hasValueFlow=36.1
|
||||
sink a[2] # $ hasValueFlow=36.1
|
||||
sink a[0]
|
||||
sink a[1]
|
||||
sink a[2]
|
||||
end
|
||||
|
||||
def m37(i)
|
||||
|
||||
1231
ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected
Normal file
1231
ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected
Normal file
File diff suppressed because it is too large
Load Diff
15
ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.ql
Normal file
15
ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import TestUtilities.InlineFlowTest
|
||||
import PathGraph
|
||||
|
||||
class HasFlowTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getTaintFlowConfig() { none() }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
725
ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb
Normal file
725
ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb
Normal file
@@ -0,0 +1,725 @@
|
||||
def taint x
|
||||
x
|
||||
end
|
||||
|
||||
def sink x
|
||||
puts x
|
||||
end
|
||||
|
||||
def m1()
|
||||
hash = {
|
||||
:a => taint(1.1),
|
||||
:b => 1,
|
||||
c: taint(1.2),
|
||||
d: 2,
|
||||
'e': taint(1.3),
|
||||
'f': 3,
|
||||
'g' => taint(1.4),
|
||||
'h' => 4,
|
||||
0 => taint(1.5),
|
||||
1 => 5
|
||||
}
|
||||
sink(hash[:a]) # $ hasValueFlow=1.1
|
||||
sink(hash[:b])
|
||||
sink(hash[:c]) # $ hasValueFlow=1.2
|
||||
sink(hash[:d])
|
||||
sink(hash['e']) # $ hasValueFlow=1.3
|
||||
sink(hash['f'])
|
||||
sink(hash['g']) # $ hasValueFlow=1.4
|
||||
sink(hash['h'])
|
||||
sink(hash[0]) # $ hasValueFlow=1.5
|
||||
sink(hash[1])
|
||||
end
|
||||
|
||||
m1()
|
||||
|
||||
def m2()
|
||||
hash = Hash.new
|
||||
hash[0] = taint(2.1)
|
||||
hash[1] = 1
|
||||
hash[:a] = taint(2.2)
|
||||
hash[:b] = 2
|
||||
hash['a'] = taint(2.3)
|
||||
hash['b'] = 3
|
||||
sink(hash[0]) # $ hasValueFlow=2.1
|
||||
sink(hash[1])
|
||||
sink(hash[:a]) # $ hasValueFlow=2.2
|
||||
sink(hash[:b])
|
||||
sink(hash['a']) # $ hasValueFlow=2.3
|
||||
sink(hash['b'])
|
||||
end
|
||||
|
||||
m2()
|
||||
|
||||
def m3()
|
||||
hash1 = Hash[a: taint(3.1), b: 1]
|
||||
sink(hash1[:a]) # $ hasValueFlow=3.1
|
||||
sink(hash1[:b])
|
||||
|
||||
x = {a: taint(3.2), b: 1}
|
||||
hash2 = Hash[x]
|
||||
sink(hash2[:a]) # $ hasValueFlow=3.2
|
||||
sink(hash2[:b])
|
||||
|
||||
hash3 = Hash[[[:a, taint(3.3)], [:b, 1]]]
|
||||
sink(hash3[:a]) # $ hasValueFlow=3.3
|
||||
sink(hash3[:b]) # $ SPURIOUS hasValueFlow=3.3
|
||||
|
||||
hash4 = Hash[:a, taint(3.4), :b, 1]
|
||||
sink(hash4[:a]) # $ hasValueFlow=3.4
|
||||
sink(hash4[:b])
|
||||
end
|
||||
|
||||
m3()
|
||||
|
||||
def m4()
|
||||
hash1 = ::Hash.[](a: taint(4.1), b: 1)
|
||||
sink(hash1[:a]) # $ hasValueFlow=4.1
|
||||
sink(hash1[:b])
|
||||
end
|
||||
|
||||
m4()
|
||||
|
||||
def m5()
|
||||
hash = {
|
||||
:a => taint(5.1),
|
||||
:b => 1
|
||||
}
|
||||
hash2 = Hash.try_convert(hash)
|
||||
sink(hash2[:a]) # $ hasValueFlow=5.1
|
||||
sink(hash2[:b])
|
||||
end
|
||||
|
||||
m5()
|
||||
|
||||
def m6()
|
||||
hash = Hash.new
|
||||
b = (hash[:a] = taint(6.1))
|
||||
sink(b) # $ hasValueFlow=6.1
|
||||
end
|
||||
|
||||
m6()
|
||||
|
||||
def m7(x)
|
||||
hash = Hash.new
|
||||
b = hash.store(:a, taint(7.1))
|
||||
sink(hash[:a]) # $ hasValueFlow=7.1
|
||||
sink(b) # $ hasValueFlow=7.1
|
||||
hash.store(:a, 1)
|
||||
sink(hash[:a])
|
||||
c = hash.store(x, taint(7.2))
|
||||
sink(hash[:a]) # $ hasValueFlow=7.2
|
||||
sink(hash[10]) # $ hasValueFlow=7.2
|
||||
sink(c) # $ hasValueFlow=7.2
|
||||
end
|
||||
|
||||
m7("foo")
|
||||
|
||||
def m8()
|
||||
hash = {
|
||||
:a => taint(8.1),
|
||||
:b => 1
|
||||
}
|
||||
hash.any? { |key_or_value|
|
||||
sink(key_or_value) # $ hasValueFlow=8.1
|
||||
}
|
||||
hash.any? { |key,value|
|
||||
sink(key)
|
||||
sink(value) # $ hasValueFlow=8.1
|
||||
}
|
||||
end
|
||||
|
||||
m8()
|
||||
|
||||
def m9(x, y)
|
||||
hash = {
|
||||
:a => taint(10.1),
|
||||
:b => 1
|
||||
}
|
||||
b = hash.assoc(:a)
|
||||
sink(b[0])
|
||||
sink(b[1]) # $ hasValueFlow=10.1
|
||||
sink(b[x]) # $ hasValueFlow=10.1
|
||||
c = hash.assoc(y)
|
||||
sink(c[1]) # $ hasValueFlow=10.1
|
||||
end
|
||||
|
||||
m9(1, :a)
|
||||
|
||||
def m10()
|
||||
hash = {
|
||||
:a => taint(9.1),
|
||||
:b => 1
|
||||
}
|
||||
hash.clear
|
||||
sink(hash[:a])
|
||||
end
|
||||
|
||||
m10()
|
||||
|
||||
def m11()
|
||||
hash = {
|
||||
:a => taint(11.1),
|
||||
:b => 1
|
||||
}
|
||||
a = hash.compact
|
||||
sink(a[:a]) # $ hasValueFlow=11.1
|
||||
sink(a[:b])
|
||||
end
|
||||
|
||||
m11()
|
||||
|
||||
def m12()
|
||||
hash = {
|
||||
:a => taint(12.1),
|
||||
:b => 1
|
||||
}
|
||||
a = hash.delete(:a)
|
||||
sink(a) # $ hasValueFlow=12.1
|
||||
sink(hash[:a])
|
||||
end
|
||||
|
||||
m12()
|
||||
|
||||
def m13()
|
||||
hash = {
|
||||
:a => taint(13.1),
|
||||
:b => 1
|
||||
}
|
||||
a = hash.delete_if do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=13.1
|
||||
end
|
||||
sink(a[:a]) # $ hasValueFlow=13.1
|
||||
sink(hash[:a]) # $ hasValueFlow=13.1
|
||||
sink(hash[0])
|
||||
end
|
||||
|
||||
m13()
|
||||
|
||||
def m14()
|
||||
hash = {
|
||||
:a => taint(14.1),
|
||||
:b => 1,
|
||||
:c => {
|
||||
:d => taint(14.2),
|
||||
:e => 2
|
||||
}
|
||||
}
|
||||
sink(hash.dig(:a)) # $ hasValueFlow=14.1
|
||||
sink(hash.dig(:b))
|
||||
sink(hash.dig(:c,:d)) # $ hasValueFlow=14.2
|
||||
sink(hash.dig(:c,:e))
|
||||
end
|
||||
|
||||
m14()
|
||||
|
||||
def m15()
|
||||
hash = {
|
||||
:a => taint(15.1),
|
||||
:b => 1
|
||||
}
|
||||
x = hash.each do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=15.1
|
||||
end
|
||||
sink(x[:a]) # $ hasValueFlow=15.1
|
||||
sink(x[:b])
|
||||
end
|
||||
|
||||
m15()
|
||||
|
||||
def m16()
|
||||
hash = {
|
||||
:a => taint(16.1),
|
||||
:b => 1
|
||||
}
|
||||
x = hash.each_key do |key|
|
||||
sink key
|
||||
end
|
||||
sink(x[:a]) # $ hasValueFlow=16.1
|
||||
sink(x[:b])
|
||||
end
|
||||
|
||||
m16()
|
||||
|
||||
def m17()
|
||||
hash = {
|
||||
:a => taint(17.1),
|
||||
:b => 1
|
||||
}
|
||||
x = hash.each_pair do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=17.1
|
||||
end
|
||||
sink(x[:a]) # $ hasValueFlow=17.1
|
||||
sink(x[:b])
|
||||
end
|
||||
|
||||
m17()
|
||||
|
||||
def m18()
|
||||
hash = {
|
||||
:a => taint(18.1),
|
||||
:b => 1
|
||||
}
|
||||
x = hash.each_value do |value|
|
||||
sink value # $ hasValueFlow=18.1
|
||||
end
|
||||
sink(x[:a]) # $ hasValueFlow=18.1
|
||||
sink(x[:b])
|
||||
end
|
||||
|
||||
m18()
|
||||
|
||||
def m19(x)
|
||||
hash = {
|
||||
:a => taint(19.1),
|
||||
:b => 1,
|
||||
:c => taint(19.2),
|
||||
:d => taint(19.3)
|
||||
}
|
||||
x = hash.except(:a,x,:d)
|
||||
sink(x[:a])
|
||||
sink(x[:b])
|
||||
sink(x[:c]) # $ hasValueFlow=19.2
|
||||
sink(x[:d])
|
||||
end
|
||||
|
||||
m19(:c)
|
||||
|
||||
def m20(x)
|
||||
hash = {
|
||||
:a => taint(20.1),
|
||||
:b => 1,
|
||||
:c => taint(20.2)
|
||||
}
|
||||
b = hash.fetch(taint(20.3)) do |x|
|
||||
sink x # $ hasValueFlow=20.3
|
||||
end
|
||||
sink(b) # $ hasValueFlow=20.1 $ hasValueFlow=20.2
|
||||
b = hash.fetch(:a)
|
||||
sink b # $ hasValueFlow=20.1
|
||||
b = hash.fetch(:a, taint(20.4))
|
||||
sink b # $ hasValueFlow=20.1 $ hasValueFlow=20.4
|
||||
b = hash.fetch(:b, taint(20.5))
|
||||
sink b # $ hasValueFlow=20.5
|
||||
b = hash.fetch(x, taint(20.6))
|
||||
sink b # $ hasValueFlow=20.1 $ hasValueFlow=20.2 $ hasValueFlow=20.6
|
||||
end
|
||||
|
||||
m20(:a)
|
||||
|
||||
def m21(x)
|
||||
hash = {
|
||||
:a => taint(21.1),
|
||||
:b => 1,
|
||||
:c => taint(21.2)
|
||||
}
|
||||
b = hash.fetch_values(taint(21.3)) do |x|
|
||||
sink x # $ hasValueFlow=21.3
|
||||
taint(21.4)
|
||||
end
|
||||
sink(b[0]) # $ hasValueFlow=21.1 $ hasValueFlow=21.2 $ hasValueFlow=21.4
|
||||
b = hash.fetch_values(:a)
|
||||
sink(b[0]) # $ hasValueFlow=21.1
|
||||
b = hash.fetch_values(:a,x)
|
||||
sink(b[1]) # $ hasValueFlow=21.1 $ hasValueFlow=21.2
|
||||
end
|
||||
|
||||
m21(:c)
|
||||
|
||||
def m22()
|
||||
hash = {
|
||||
:a => taint(22.1),
|
||||
:b => 1,
|
||||
:c => taint(22.2)
|
||||
}
|
||||
b = hash.filter do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=22.1 $ hasValueFlow=22.2
|
||||
true
|
||||
end
|
||||
sink (b[:a]) # $ hasValueFlow=22.1
|
||||
end
|
||||
|
||||
m22()
|
||||
|
||||
def m23()
|
||||
hash = {
|
||||
:a => taint(23.1),
|
||||
:b => 1,
|
||||
:c => taint(23.2)
|
||||
}
|
||||
hash.filter! do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=23.1 $ hasValueFlow=23.2
|
||||
true
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=23.1
|
||||
end
|
||||
|
||||
m23()
|
||||
|
||||
def m24()
|
||||
hash = {
|
||||
:a => taint(24.1),
|
||||
:b => 1,
|
||||
:c => taint(24.2)
|
||||
}
|
||||
b = hash.flatten
|
||||
sink (b[1]) # $ hasValueFlow=24.1 $ hasValueFlow=24.2
|
||||
end
|
||||
|
||||
m24()
|
||||
|
||||
def m25()
|
||||
hash = {
|
||||
:a => taint(25.1),
|
||||
:b => 1,
|
||||
:c => taint(25.2)
|
||||
}
|
||||
b = hash.keep_if do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=25.1 $ hasValueFlow=25.2
|
||||
true
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=25.1
|
||||
sink (b[:a]) # $ hasValueFlow=25.1
|
||||
end
|
||||
|
||||
m25()
|
||||
|
||||
def m26()
|
||||
hash1 = {
|
||||
:a => taint(26.1),
|
||||
:b => 1,
|
||||
:c => taint(26.2)
|
||||
}
|
||||
hash2 = {
|
||||
:d => taint(26.3),
|
||||
:e => 1,
|
||||
:f => taint(26.4)
|
||||
}
|
||||
hash = hash1.merge(hash2) do |key, old_value, new_value|
|
||||
sink key
|
||||
sink old_value # $ hasValueFlow=26.1 $ hasValueFlow=26.2 $ hasValueFlow=26.3 $ hasValueFlow=26.4
|
||||
sink new_value # $ hasValueFlow=26.1 $ hasValueFlow=26.2 $ hasValueFlow=26.3 $ hasValueFlow=26.4
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=26.1
|
||||
sink (hash[:b])
|
||||
sink (hash[:c]) # $ hasValueFlow=26.2
|
||||
sink (hash[:d]) # $ hasValueFlow=26.3
|
||||
sink (hash[:e])
|
||||
sink (hash[:f]) # $ hasValueFlow=26.4
|
||||
end
|
||||
|
||||
m26()
|
||||
|
||||
def m27()
|
||||
hash1 = {
|
||||
:a => taint(27.1),
|
||||
:b => 1,
|
||||
:c => taint(27.2)
|
||||
}
|
||||
hash2 = {
|
||||
:d => taint(27.3),
|
||||
:e => 1,
|
||||
:f => taint(27.4)
|
||||
}
|
||||
hash = hash1.merge!(hash2) do |key, old_value, new_value|
|
||||
sink key
|
||||
sink old_value # $ hasValueFlow=27.1 $ hasValueFlow=27.2 $ hasValueFlow=27.3 $ hasValueFlow=27.4
|
||||
sink new_value # $ hasValueFlow=27.1 $ hasValueFlow=27.2 $ hasValueFlow=27.3 $ hasValueFlow=27.4
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=27.1
|
||||
sink (hash[:b])
|
||||
sink (hash[:c]) # $ hasValueFlow=27.2
|
||||
sink (hash[:d]) # $ hasValueFlow=27.3
|
||||
sink (hash[:e])
|
||||
sink (hash[:f]) # $ hasValueFlow=27.4
|
||||
|
||||
sink (hash1[:a]) # $ hasValueFlow=27.1
|
||||
sink (hash1[:b])
|
||||
sink (hash1[:c]) # $ hasValueFlow=27.2
|
||||
sink (hash1[:d]) # $ hasValueFlow=27.3
|
||||
sink (hash1[:e])
|
||||
sink (hash1[:f]) # $ hasValueFlow=27.4
|
||||
end
|
||||
|
||||
m27()
|
||||
|
||||
def m28
|
||||
hash = {
|
||||
:a => taint(28.1),
|
||||
:b => 1
|
||||
}
|
||||
b = hash.rassoc(0)
|
||||
sink(b[0])
|
||||
sink(b[1]) # $ hasValueFlow=28.1
|
||||
end
|
||||
|
||||
m28()
|
||||
|
||||
def m29
|
||||
hash = {
|
||||
:a => taint(29.1),
|
||||
:b => 1
|
||||
}
|
||||
b = hash.reject do |key,value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=29.1
|
||||
value > 10
|
||||
end
|
||||
sink b[:a] # $ hasValueFlow=29.1
|
||||
end
|
||||
|
||||
m29()
|
||||
|
||||
def m30
|
||||
hash = {
|
||||
:a => taint(30.1),
|
||||
:b => 1
|
||||
}
|
||||
b = hash.reject! do |key,value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=30.1
|
||||
value > 10
|
||||
end
|
||||
sink b[:a] # $ hasValueFlow=30.1
|
||||
sink hash[:a] # $ hasValueFlow=30.1
|
||||
end
|
||||
|
||||
m30()
|
||||
|
||||
def m31()
|
||||
hash = {
|
||||
:a => taint(31.1),
|
||||
:b => 1,
|
||||
:c => taint(31.2)
|
||||
}
|
||||
hash2 = {
|
||||
:c => taint(31.3)
|
||||
}
|
||||
hash2.replace(hash)
|
||||
sink (hash2[:a]) # $ hasValueFlow=31.1
|
||||
sink (hash2[:b])
|
||||
sink (hash2[:c]) # $ hasValueFlow=31.2
|
||||
end
|
||||
|
||||
def m32()
|
||||
hash = {
|
||||
:a => taint(32.1),
|
||||
:b => 1,
|
||||
:c => taint(32.2)
|
||||
}
|
||||
b = hash.select do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=32.1 $ hasValueFlow=32.2
|
||||
true
|
||||
end
|
||||
sink (b[:a]) # $ hasValueFlow=32.1
|
||||
end
|
||||
|
||||
m32()
|
||||
|
||||
def m33()
|
||||
hash = {
|
||||
:a => taint(33.1),
|
||||
:b => 1,
|
||||
:c => taint(33.2)
|
||||
}
|
||||
hash.select! do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=33.1 $ hasValueFlow=33.2
|
||||
true
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=33.1
|
||||
end
|
||||
|
||||
m33()
|
||||
|
||||
def m34()
|
||||
hash = {
|
||||
:a => taint(34.1),
|
||||
:b => 1,
|
||||
:c => taint(34.2)
|
||||
}
|
||||
b = hash.shift
|
||||
sink (hash[:a]) # $ hasValueFlow=34.1
|
||||
sink (b[0])
|
||||
sink (b[1]) # $ hasValueFlow=34.1 $ hasValueFlow=34.2
|
||||
end
|
||||
|
||||
m34()
|
||||
|
||||
def m35(x)
|
||||
hash = {
|
||||
:a => taint(35.1),
|
||||
:b => 1,
|
||||
:c => taint(35.2)
|
||||
}
|
||||
b = hash.slice(:a, :b)
|
||||
sink (b[:a]) # $ hasValueFlow=35.1
|
||||
sink (b[:b])
|
||||
sink (b[:c])
|
||||
|
||||
c = hash.slice(:a, x)
|
||||
sink (c[:a]) # $ hasValueFlow=35.1
|
||||
sink (c[:b])
|
||||
sink (c[:c]) # $ hasValueFlow=35.2
|
||||
end
|
||||
|
||||
m35(:c)
|
||||
|
||||
def m36()
|
||||
hash = {
|
||||
:a => taint(36.1),
|
||||
:b => 1,
|
||||
:c => taint(36.2)
|
||||
}
|
||||
a = hash.to_a
|
||||
sink (a[0][0])
|
||||
sink (a[0][1]) # $ hasValueFlow=36.1 $ hasValueFlow=36.2
|
||||
end
|
||||
|
||||
m36()
|
||||
|
||||
def m37()
|
||||
hash = {
|
||||
:a => taint(37.1),
|
||||
:b => 1,
|
||||
:c => taint(37.2)
|
||||
}
|
||||
a = hash.to_h
|
||||
sink (a[:a]) # $ hasValueFlow=37.1
|
||||
sink (a[:b])
|
||||
sink (a[:c]) # $ hasValueFlow=37.2
|
||||
|
||||
b = hash.to_h do |key, value|
|
||||
sink key
|
||||
sink value # $ hasValueFlow=37.1 $ hasValueFlow=37.2
|
||||
[:d, taint(37.3)]
|
||||
end
|
||||
sink (b[:d]) # $ hasValueFlow=37.3
|
||||
end
|
||||
|
||||
m37()
|
||||
|
||||
def m38()
|
||||
hash = {
|
||||
:a => taint(38.1),
|
||||
:b => 1,
|
||||
:c => taint(38.2)
|
||||
}
|
||||
a = hash.transform_keys {|key| key.to_s }
|
||||
sink (a["a"]) # $ hasValueFlow=38.1 $ hasValueFlow=38.2
|
||||
sink (a["b"]) # $ hasValueFlow=38.1 $ hasValueFlow=38.2
|
||||
sink (a["c"]) # $ hasValueFlow=38.1 $ hasValueFlow=38.2
|
||||
end
|
||||
|
||||
m38()
|
||||
|
||||
def m39()
|
||||
hash = {
|
||||
:a => taint(39.1),
|
||||
:b => 1,
|
||||
:c => taint(39.2)
|
||||
}
|
||||
hash.transform_keys! {|key| key.to_s }
|
||||
sink (hash["a"]) # $ hasValueFlow=39.1 $ hasValueFlow=39.2
|
||||
sink (hash["b"]) # $ hasValueFlow=39.1 $ hasValueFlow=39.2
|
||||
sink (hash["c"]) # $ hasValueFlow=39.1 $ hasValueFlow=39.2
|
||||
end
|
||||
|
||||
m39()
|
||||
|
||||
def m40()
|
||||
hash = {
|
||||
:a => taint(40.1),
|
||||
:b => 1,
|
||||
:c => taint(40.2)
|
||||
}
|
||||
b = hash.transform_values do |value|
|
||||
sink value # $ hasValueFlow=40.1 $ hasValueFlow=40.2
|
||||
taint(40.3)
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=40.1
|
||||
sink (b[:a]) # $ hasValueFlow=40.3
|
||||
end
|
||||
|
||||
m40()
|
||||
|
||||
def m41()
|
||||
hash = {
|
||||
:a => taint(41.1),
|
||||
:b => 1,
|
||||
:c => taint(41.2)
|
||||
}
|
||||
hash.transform_values! do |value|
|
||||
sink value # $ hasValueFlow=41.1 $ hasValueFlow=41.2
|
||||
taint(41.3)
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=41.3
|
||||
end
|
||||
|
||||
m41()
|
||||
|
||||
def m42()
|
||||
hash1 = {
|
||||
:a => taint(42.1),
|
||||
:b => 1,
|
||||
:c => taint(42.2)
|
||||
}
|
||||
hash2 = {
|
||||
:d => taint(42.3),
|
||||
:e => 1,
|
||||
:f => taint(42.4)
|
||||
}
|
||||
hash = hash1.update(hash2) do |key, old_value, new_value|
|
||||
sink key
|
||||
sink old_value # $ hasValueFlow=42.1 $ hasValueFlow=42.2 $ hasValueFlow=42.3 $ hasValueFlow=42.4
|
||||
sink new_value # $ hasValueFlow=42.1 $ hasValueFlow=42.2 $ hasValueFlow=42.3 $ hasValueFlow=42.4
|
||||
end
|
||||
sink (hash[:a]) # $ hasValueFlow=42.1
|
||||
sink (hash[:b])
|
||||
sink (hash[:c]) # $ hasValueFlow=42.2
|
||||
sink (hash[:d]) # $ hasValueFlow=42.3
|
||||
sink (hash[:e])
|
||||
sink (hash[:f]) # $ hasValueFlow=42.4
|
||||
|
||||
sink (hash1[:a]) # $ hasValueFlow=42.1
|
||||
sink (hash1[:b])
|
||||
sink (hash1[:c]) # $ hasValueFlow=42.2
|
||||
sink (hash1[:d]) # $ hasValueFlow=42.3
|
||||
sink (hash1[:e])
|
||||
sink (hash1[:f]) # $ hasValueFlow=42.4
|
||||
end
|
||||
|
||||
m42()
|
||||
|
||||
def m43()
|
||||
hash = {
|
||||
:a => taint(43.1),
|
||||
:b => 1,
|
||||
:c => taint(43.2)
|
||||
}
|
||||
a = hash.values
|
||||
sink (a[0]) # $ hasValueFlow=43.1 # $ hasValueFlow=43.2
|
||||
end
|
||||
|
||||
m43()
|
||||
|
||||
def m44(x)
|
||||
hash = {
|
||||
:a => taint(44.1),
|
||||
:b => 1,
|
||||
:c => taint(44.2)
|
||||
}
|
||||
b = hash.values_at(:a)
|
||||
sink(b[0]) # $ hasValueFlow=44.1
|
||||
b = hash.fetch_values(:a,x)
|
||||
sink(b[1]) # $ hasValueFlow=44.1 $ hasValueFlow=44.2
|
||||
end
|
||||
|
||||
m44(:c)
|
||||
@@ -10,6 +10,8 @@ edges
|
||||
| params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
|
||||
| params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
|
||||
| params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:16:13:16:14 | p1 : |
|
||||
| params_flow.rb:23:16:23:23 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
|
||||
| params_flow.rb:23:33:23:40 | call to taint : | params_flow.rb:16:13:16:14 | p1 : |
|
||||
nodes
|
||||
| params_flow.rb:9:16:9:17 | p1 : | semmle.label | p1 : |
|
||||
| params_flow.rb:9:20:9:21 | p2 : | semmle.label | p2 : |
|
||||
@@ -25,11 +27,15 @@ nodes
|
||||
| params_flow.rb:21:27:21:34 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:22:13:22:20 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:22:27:22:34 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:23:16:23:23 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:23:33:23:40 | call to taint : | semmle.label | call to taint : |
|
||||
subpaths
|
||||
#select
|
||||
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:14:12:14:19 | call to taint : | call to taint : |
|
||||
| params_flow.rb:11:10:11:11 | p2 | params_flow.rb:14:22:14:29 | call to taint : | params_flow.rb:11:10:11:11 | p2 | $@ | params_flow.rb:14:22:14:29 | call to taint : | call to taint : |
|
||||
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:21:13:21:20 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:21:13:21:20 | call to taint : | call to taint : |
|
||||
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:22:27:22:34 | call to taint : | call to taint : |
|
||||
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:23:33:23:40 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:23:33:23:40 | call to taint : | call to taint : |
|
||||
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:21:27:21:34 | call to taint : | call to taint : |
|
||||
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:22:13:22:20 | call to taint : | call to taint : |
|
||||
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:23:16:23:23 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:23:16:23:23 | call to taint : | call to taint : |
|
||||
|
||||
@@ -14,9 +14,10 @@ end
|
||||
positional(taint(1), taint(2))
|
||||
|
||||
def keyword(p1:, p2:)
|
||||
sink p1 # $ hasValueFlow=3 $ hasValueFlow=6
|
||||
sink p2 # $ hasValueFlow=4 $ hasValueFlow=5
|
||||
sink p1 # $ hasValueFlow=3 $ hasValueFlow=6 $ hasValueFlow=8
|
||||
sink p2 # $ hasValueFlow=4 $ hasValueFlow=5 $ hasValueFlow=7
|
||||
end
|
||||
|
||||
keyword(p1: taint(3), p2: taint(4))
|
||||
keyword(p2: taint(5), p1: taint(6))
|
||||
keyword(:p2 => taint(7), :p1 => taint(8))
|
||||
|
||||
@@ -249,7 +249,6 @@ edges
|
||||
| string_flow.rb:283:9:283:9 | a : | string_flow.rb:283:9:283:14 | ...[...] : |
|
||||
| string_flow.rb:283:9:283:9 | a : | string_flow.rb:283:9:283:14 | ...[...] [element 0] : |
|
||||
| string_flow.rb:283:9:283:9 | a : | string_flow.rb:283:9:283:14 | ...[...] [element 1] : |
|
||||
| string_flow.rb:283:9:283:9 | a : | string_flow.rb:283:9:283:14 | ...[...] [element] : |
|
||||
| string_flow.rb:283:9:283:9 | a [element 1] : | string_flow.rb:283:9:283:14 | ...[...] [element 0] : |
|
||||
| string_flow.rb:283:9:283:9 | a [element 2] : | string_flow.rb:283:9:283:14 | ...[...] [element 1] : |
|
||||
| string_flow.rb:283:9:283:9 | a [element] : | string_flow.rb:283:9:283:14 | ...[...] [element] : |
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
| tst-IncompleteHostnameRegExp.rb:17:14:17:30 | test.example.com$ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:17:13:17:31 | `test.example.com$` | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:19:14:19:30 | ^test.example.com | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:20:13:20:26 | "#{...}$" | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:20:14:20:31 | ^test.example.com$ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:20:13:20:26 | "#{...}$" | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:22:24:22:40 | test.example.com$ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:23:13:23:29 | ...[...] | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:28:24:28:40 | test.example.com$ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:63:20:63:36 | ...[...] | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:30:27:30:43 | test.example.com$ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:66:20:66:36 | ...[...] | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:37:3:37:53 | ^(https?:)?\\/\\/((service\|www).)?example.com(?=$\|\\/) | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:37:2:37:54 | /^(https?:)?\\/\\/((service\|www).../ | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:38:3:38:43 | ^(http\|https):\\/\\/www.example.com\\/p\\/f\\/ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:38:2:38:44 | /^(http\|https):\\/\\/www.example.../ | here |
|
||||
| tst-IncompleteHostnameRegExp.rb:39:5:39:30 | http:\\/\\/sub.example.com\\/ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:39:2:39:33 | /^(http:\\/\\/sub.example.com\\/)/ | here |
|
||||
|
||||
Reference in New Issue
Block a user