mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Ruby: merge package/type columns
This commit is contained in:
@@ -474,7 +474,7 @@ private module Cached {
|
||||
// external model data. This, unfortunately, does not included any field names used
|
||||
// in models defined in QL code.
|
||||
exists(string input, string output |
|
||||
ModelOutput::relevantSummaryModel(_, _, _, input, output, _)
|
||||
ModelOutput::relevantSummaryModel(_, _, input, output, _)
|
||||
|
|
||||
name = [input, output].regexpFind("(?<=(^|\\.)Field\\[)[^\\]]+(?=\\])", _, _).trim()
|
||||
)
|
||||
|
||||
@@ -21,23 +21,21 @@ module ActionDispatch {
|
||||
*/
|
||||
private class MimeTypeTypeSummary extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package1;type1;package2;type2;path
|
||||
// type1;type2;path
|
||||
row =
|
||||
[
|
||||
// Mime[type] : Mime::Type (omitted)
|
||||
// Method names with brackets like [] cannot be represented in MaD.
|
||||
// Mime.fetch(type) : Mime::Type
|
||||
"actiondispatch;Mime::Type;;;Member[Mime].Method[fetch].ReturnValue",
|
||||
// Mime::Type.new(str) : Mime::Type
|
||||
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Instance",
|
||||
"Mime::Type;Mime!;Method[fetch].ReturnValue",
|
||||
// Mime::Type.lookup(str) : Mime::Type
|
||||
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[lookup].ReturnValue",
|
||||
"Mime::Type;Mime::Type!;Method[lookup].ReturnValue",
|
||||
// Mime::Type.lookup_by_extension(str) : Mime::Type
|
||||
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[lookup_by_extension].ReturnValue",
|
||||
"Mime::Type;Mime::Type!;Method[lookup_by_extension].ReturnValue",
|
||||
// Mime::Type.register(str) : Mime::Type
|
||||
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[register].ReturnValue",
|
||||
"Mime::Type;Mime::Type!;Method[register].ReturnValue",
|
||||
// Mime::Type.register_alias(str) : Mime::Type
|
||||
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[register_alias].ReturnValue",
|
||||
"Mime::Type;Mime::Type!;Method[register_alias].ReturnValue",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -48,10 +46,7 @@ module ActionDispatch {
|
||||
*/
|
||||
class MimeTypeMatchRegExpInterpretation extends RE::RegExpInterpretation::Range {
|
||||
MimeTypeMatchRegExpInterpretation() {
|
||||
this =
|
||||
ModelOutput::getATypeNode("actiondispatch", "Mime::Type")
|
||||
.getAMethodCall(["match?", "=~"])
|
||||
.getArgument(0)
|
||||
this = ModelOutput::getATypeNode("Mime::Type").getAMethodCall(["match?", "=~"]).getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ module ActiveStorage {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"activestorage;;Member[ActiveStorage].Member[Filename].Method[new];Argument[0];ReturnValue;taint",
|
||||
"activestorage;;Member[ActiveStorage].Member[Filename].Instance.Method[sanitized];Argument[self];ReturnValue;taint",
|
||||
"ActiveStorage::Filename!;Method[new];Argument[0];ReturnValue;taint",
|
||||
"ActiveStorage::Filename;Method[sanitized];Argument[self];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -45,25 +45,23 @@ module ActiveStorage {
|
||||
// package1;type1;package2;type2;path
|
||||
row =
|
||||
[
|
||||
// ActiveStorage::Blob.new : Blob
|
||||
"activestorage;Blob;activestorage;;Member[ActiveStorage].Member[Blob].Instance",
|
||||
// ActiveStorage::Blob.create_and_upload! : Blob
|
||||
"activestorage;Blob;activestorage;;Member[ActiveStorage].Member[Blob].Method[create_and_upload!].ReturnValue",
|
||||
"ActiveStorage::Blob;ActiveStorage::Blob!;Method[create_and_upload!].ReturnValue",
|
||||
// ActiveStorage::Blob.create_before_direct_upload! : Blob
|
||||
"activestorage;Blob;activestorage;;Member[ActiveStorage].Member[Blob].Method[create_before_direct_upload!].ReturnValue",
|
||||
"ActiveStorage::Blob;ActiveStorage::Blob!;Method[create_before_direct_upload!].ReturnValue",
|
||||
// ActiveStorage::Blob.compose(blobs : [Blob]) : Blob
|
||||
"activestorage;Blob;activestorage;;Member[ActiveStorage].Member[Blob].Method[compose].ReturnValue",
|
||||
"ActiveStorage::Blob;ActiveStorage::Blob!;Method[compose].ReturnValue",
|
||||
// gives error: Invalid name 'Element' in access path
|
||||
// "activestorage;Blob;activestorage;;Member[ActiveStorage].Member[Blob].Method[compose].Argument[0].Element[any]",
|
||||
// "ActiveStorage::Blob;ActiveStorage::Blob!;Method[compose].Argument[0].Element[any]",
|
||||
// ActiveStorage::Blob.find_signed(!) : Blob
|
||||
"activestorage;Blob;activestorage;;Member[ActiveStorage].Member[Blob].Method[find_signed,find_signed!].ReturnValue",
|
||||
"ActiveStorage::Blob;ActiveStorage::Blob!;Method[find_signed,find_signed!].ReturnValue",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private class BlobInstance extends DataFlow::Node {
|
||||
BlobInstance() {
|
||||
this = ModelOutput::getATypeNode("activestorage", "Blob").getAValueReachableFromSource()
|
||||
this = ModelOutput::getATypeNode("ActiveStorage::Blob").getAValueReachableFromSource()
|
||||
or
|
||||
// ActiveStorage::Attachment#blob : Blob
|
||||
exists(DataFlow::CallNode call |
|
||||
|
||||
@@ -317,9 +317,9 @@ module ActiveSupport {
|
||||
*/
|
||||
private class PathnameTypeSummary extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package1;type1;package2;type2;path
|
||||
// type1;type2;path
|
||||
// Pathname#existence : Pathname
|
||||
row = ";Pathname;;Pathname;Method[existence].ReturnValue"
|
||||
row = "Pathname;Pathname;Method[existence].ReturnValue"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ module ActiveSupport {
|
||||
private class PathnameTaintSummary extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
// Pathname#existence
|
||||
row = ";Pathname;Method[existence];Argument[self];ReturnValue;taint"
|
||||
row = "Pathname;Method[existence];Argument[self];ReturnValue;taint"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,12 +345,12 @@ module ActiveSupport {
|
||||
row =
|
||||
[
|
||||
// SafeBuffer.new(x) does not sanitize x
|
||||
"activesupport;;Member[ActionView].Member[SafeBuffer].Method[new];Argument[0];ReturnValue;taint",
|
||||
"ActionView::SafeBuffer!;Method[new];Argument[0];ReturnValue;taint",
|
||||
// SafeBuffer#safe_concat(x) does not sanitize x
|
||||
"activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[safe_concat];Argument[0];ReturnValue;taint",
|
||||
"activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[safe_concat];Argument[0];Argument[self];taint",
|
||||
"ActionView::SafeBuffer;Method[safe_concat];Argument[0];ReturnValue;taint",
|
||||
"ActionView::SafeBuffer;Method[safe_concat];Argument[0];Argument[self];taint",
|
||||
// These methods preserve taint in self
|
||||
"activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[concat,insert,prepend,to_s,to_param];Argument[self];ReturnValue;taint",
|
||||
"ActionView::SafeBuffer;Method[concat,insert,prepend,to_s,to_param];Argument[self];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ module Regexp {
|
||||
/** A flow summary for `Regexp.escape` and its alias, `Regexp.quote`. */
|
||||
class RegexpEscapeSummary extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row = ";;Member[Regexp].Method[escape,quote];Argument[0];ReturnValue;taint"
|
||||
row = "Regexp!;Method[escape,quote];Argument[0];ReturnValue;taint"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,26 +33,23 @@ private class RemoteFlowSourceFromCsv extends RemoteFlowSource::Range {
|
||||
}
|
||||
|
||||
private class SummarizedCallableFromModel extends SummarizedCallable {
|
||||
string package;
|
||||
string type;
|
||||
string path;
|
||||
|
||||
SummarizedCallableFromModel() {
|
||||
ModelOutput::relevantSummaryModel(package, type, path, _, _, _) and
|
||||
this = package + ";" + type + ";" + path
|
||||
ModelOutput::relevantSummaryModel(type, path, _, _, _) and
|
||||
this = type + ";" + path
|
||||
}
|
||||
|
||||
override Call getACall() {
|
||||
exists(API::MethodAccessNode base |
|
||||
ModelOutput::resolvedSummaryBase(package, type, path, base) and
|
||||
ModelOutput::resolvedSummaryBase(type, path, base) and
|
||||
result = base.getCallNode().asExpr().getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
exists(string kind |
|
||||
ModelOutput::relevantSummaryModel(package, type, path, input, output, kind)
|
||||
|
|
||||
exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind) |
|
||||
kind = "value" and
|
||||
preservesValue = true
|
||||
or
|
||||
|
||||
@@ -5,23 +5,20 @@
|
||||
*
|
||||
* The CSV specification has the following columns:
|
||||
* - Sources:
|
||||
* `package; type; path; kind`
|
||||
* `type; path; kind`
|
||||
* - Sinks:
|
||||
* `package; type; path; kind`
|
||||
* `type; path; kind`
|
||||
* - Summaries:
|
||||
* `package; type; path; input; output; kind`
|
||||
* `type; path; input; output; kind`
|
||||
* - Types:
|
||||
* `package1; type1; package2; type2; path`
|
||||
* `type1; type2; path`
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
* 1. The `package` column selects a package name, as it would be referenced in the source code,
|
||||
* such as an NPM package, PIP package, or Ruby gem. (See `ModelsAsData.qll` for language-specific details).
|
||||
* It may also be a synthetic package used for a type definition (see type definitions below).
|
||||
* 2. The `type` column selects all instances of a named type originating from that package,
|
||||
* or the empty string if referring to the package itself.
|
||||
* 1. The `type` column selects all instances of a named type. The syntax of this column is language-specific.
|
||||
* The language defines some type names that the analysis knows how to identify without models.
|
||||
* It can also be a synthetic type name defined by a type definition (see type definitions below).
|
||||
* 3. The `path` column is a `.`-separated list of "access path tokens" to resolve, starting at the node selected by `package` and `type`.
|
||||
* 2. The `path` column is a `.`-separated list of "access path tokens" to resolve, starting at the node selected by `type`.
|
||||
*
|
||||
* Every language supports the following tokens:
|
||||
* - Argument[n]: the n-th argument to a call. May be a range of form `x..y` (inclusive) and/or a comma-separated list.
|
||||
@@ -42,10 +39,10 @@
|
||||
*
|
||||
* For the time being, please consult `ApiGraphModelsSpecific.qll` to see which language-specific tokens are currently supported.
|
||||
*
|
||||
* 4. The `input` and `output` columns specify how data enters and leaves the element selected by the
|
||||
* first `(package, type, path)` tuple. Both strings are `.`-separated access paths
|
||||
* 3. The `input` and `output` columns specify how data enters and leaves the element selected by the
|
||||
* first `(type, path)` tuple. Both strings are `.`-separated access paths
|
||||
* of the same syntax as the `path` column.
|
||||
* 5. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* 4. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
* sources `"remote"` indicates a default remote flow source, and for summaries
|
||||
* `"taint"` indicates a default additional taint step and `"value"` indicates a
|
||||
@@ -53,17 +50,17 @@
|
||||
*
|
||||
* ### Types
|
||||
*
|
||||
* A type row of form `package1; type1; package2; type2; path` indicates that `package2; type2; path`
|
||||
* should be seen as an instance of the type `package1; type1`.
|
||||
* A type row of form `type1; type2; path` indicates that `type2; path`
|
||||
* should be seen as an instance of the type `type1`.
|
||||
*
|
||||
* A `(package,type)` pair may refer to a static type or a synthetic type name used internally in the model.
|
||||
* A type may refer to a static type or a synthetic type name used internally in the model.
|
||||
* Synthetic type names can be used to reuse intermediate sub-paths, when there are multiple ways to access the same
|
||||
* element.
|
||||
* See `ModelsAsData.qll` for the language-specific interpretation of packages and static type names.
|
||||
* See `ModelsAsData.qll` for the language-specific interpretation of type names.
|
||||
*
|
||||
* By convention, if one wants to avoid clashes with static types from the package, the type name
|
||||
* should be prefixed with a tilde character (`~`). For example, `(foo, ~Bar)` can be used to indicate that
|
||||
* the type is related to the `foo` package but is not intended to match a static type.
|
||||
* By convention, if one wants to avoid clashes with static types, the type name
|
||||
* should be prefixed with a tilde character (`~`). For example, `~Bar` can be used to indicate that
|
||||
* the type is not intended to match a static type.
|
||||
*/
|
||||
|
||||
private import ApiGraphModelsSpecific as Specific
|
||||
@@ -89,9 +86,9 @@ module ModelInput {
|
||||
*
|
||||
* A row of form
|
||||
* ```
|
||||
* package;type;path;kind
|
||||
* type;path;kind
|
||||
* ```
|
||||
* indicates that the value at `(package, type, path)` should be seen as a flow
|
||||
* indicates that the value at `(type, path)` should be seen as a flow
|
||||
* source of the given `kind`.
|
||||
*
|
||||
* The kind `remote` represents a general remote flow source.
|
||||
@@ -110,9 +107,9 @@ module ModelInput {
|
||||
*
|
||||
* A row of form
|
||||
* ```
|
||||
* package;type;path;kind
|
||||
* type;path;kind
|
||||
* ```
|
||||
* indicates that the value at `(package, type, path)` should be seen as a sink
|
||||
* indicates that the value at `(type, path)` should be seen as a sink
|
||||
* of the given `kind`.
|
||||
*/
|
||||
abstract predicate row(string row);
|
||||
@@ -129,9 +126,9 @@ module ModelInput {
|
||||
*
|
||||
* A row of form
|
||||
* ```
|
||||
* package;type;path;input;output;kind
|
||||
* type;path;input;output;kind
|
||||
* ```
|
||||
* indicates that for each call to `(package, type, path)`, the value referred to by `input`
|
||||
* indicates that for each call to `(type, path)`, the value referred to by `input`
|
||||
* can flow to the value referred to by `output`.
|
||||
*
|
||||
* `kind` should be either `value` or `taint`, for value-preserving or taint-preserving steps,
|
||||
@@ -151,9 +148,9 @@ module ModelInput {
|
||||
*
|
||||
* A row of form,
|
||||
* ```
|
||||
* package1;type1;package2;type2;path
|
||||
* type1;type2;path
|
||||
* ```
|
||||
* indicates that `(package2, type2, path)` should be seen as an instance of `(package1, type1)`.
|
||||
* indicates that `(type2, path)` should be seen as an instance of `type1`.
|
||||
*/
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
@@ -163,28 +160,28 @@ module ModelInput {
|
||||
*/
|
||||
class TypeModel extends Unit {
|
||||
/**
|
||||
* Gets a data-flow node that is a source of the type `package;type`.
|
||||
* Gets a data-flow node that is a source of the given `type`.
|
||||
*
|
||||
* This must not depend on API graphs, but ensures that an API node is generated for
|
||||
* the source.
|
||||
*/
|
||||
DataFlow::Node getASource(string package, string type) { none() }
|
||||
DataFlow::Node getASource(string type) { none() }
|
||||
|
||||
/**
|
||||
* Gets a data-flow node that is a sink of the type `package;type`,
|
||||
* Gets a data-flow node that is a sink of the given `type`,
|
||||
* usually because it is an argument passed to a parameter of that type.
|
||||
*
|
||||
* This must not depend on API graphs, but ensures that an API node is generated for
|
||||
* the sink.
|
||||
*/
|
||||
DataFlow::Node getASink(string package, string type) { none() }
|
||||
DataFlow::Node getASink(string type) { none() }
|
||||
|
||||
/**
|
||||
* Gets an API node that is a source or sink of the type `package;type`.
|
||||
* Gets an API node that is a source or sink of the given `type`.
|
||||
*
|
||||
* Unlike `getASource` and `getASink`, this may depend on API graphs.
|
||||
*/
|
||||
API::Node getAnApiNode(string package, string type) { none() }
|
||||
API::Node getAnApiNode(string type) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +206,7 @@ private import ModelInput
|
||||
/**
|
||||
* An empty class, except in specific tests.
|
||||
*
|
||||
* If this is non-empty, all models are parsed even if the package is not
|
||||
* If this is non-empty, all models are parsed even if the type name is not
|
||||
* considered relevant for the current database.
|
||||
*/
|
||||
abstract class TestAllModels extends Unit { }
|
||||
@@ -232,53 +229,44 @@ private predicate typeModel(string row) { any(TypeModelCsv s).row(inversePad(row
|
||||
private predicate typeVariableModel(string row) { any(TypeVariableModelCsv s).row(inversePad(row)) }
|
||||
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate sourceModel(string package, string type, string path, string kind) {
|
||||
predicate sourceModel(string type, string path, string kind) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
row.splitAt(";", 0) = package and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = path and
|
||||
row.splitAt(";", 3) = kind
|
||||
row.splitAt(";", 0) = type and
|
||||
row.splitAt(";", 1) = path and
|
||||
row.splitAt(";", 2) = kind
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
private predicate sinkModel(string package, string type, string path, string kind) {
|
||||
private predicate sinkModel(string type, string path, string kind) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
row.splitAt(";", 0) = package and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = path and
|
||||
row.splitAt(";", 3) = kind
|
||||
row.splitAt(";", 0) = type and
|
||||
row.splitAt(";", 1) = path and
|
||||
row.splitAt(";", 2) = kind
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a summary model `row` exists for the given parameters. */
|
||||
private predicate summaryModel(
|
||||
string package, string type, string path, string input, string output, string kind
|
||||
) {
|
||||
private predicate summaryModel(string type, string path, string input, string output, string kind) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
row.splitAt(";", 0) = package and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = path and
|
||||
row.splitAt(";", 3) = input and
|
||||
row.splitAt(";", 4) = output and
|
||||
row.splitAt(";", 5) = kind
|
||||
row.splitAt(";", 0) = type and
|
||||
row.splitAt(";", 1) = path and
|
||||
row.splitAt(";", 2) = input and
|
||||
row.splitAt(";", 3) = output and
|
||||
row.splitAt(";", 4) = kind
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a type model exists for the given parameters. */
|
||||
private predicate typeModel(
|
||||
string package1, string type1, string package2, string type2, string path
|
||||
) {
|
||||
private predicate typeModel(string type1, string type2, string path) {
|
||||
exists(string row |
|
||||
typeModel(row) and
|
||||
row.splitAt(";", 0) = package1 and
|
||||
row.splitAt(";", 1) = type1 and
|
||||
row.splitAt(";", 2) = package2 and
|
||||
row.splitAt(";", 3) = type2 and
|
||||
row.splitAt(";", 4) = path
|
||||
row.splitAt(";", 0) = type1 and
|
||||
row.splitAt(";", 1) = type2 and
|
||||
row.splitAt(";", 2) = path
|
||||
)
|
||||
}
|
||||
|
||||
@@ -292,61 +280,50 @@ private predicate typeVariableModel(string name, string path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a package that should be seen as an alias for the given other `package`,
|
||||
* or the `package` itself.
|
||||
* Holds if CSV rows involving `type` might be relevant for the analysis of this database.
|
||||
*/
|
||||
bindingset[package]
|
||||
bindingset[result]
|
||||
string getAPackageAlias(string package) {
|
||||
typeModel(package, "", result, "", "")
|
||||
or
|
||||
result = package
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if CSV rows involving `package` might be relevant for the analysis of this database.
|
||||
*/
|
||||
private predicate isRelevantPackage(string package) {
|
||||
predicate isRelevantType(string type) {
|
||||
(
|
||||
sourceModel(package, _, _, _) or
|
||||
sinkModel(package, _, _, _) or
|
||||
summaryModel(package, _, _, _, _, _) or
|
||||
typeModel(_, _, package, _, _)
|
||||
sourceModel(type, _, _) or
|
||||
sinkModel(type, _, _) or
|
||||
summaryModel(type, _, _, _, _) or
|
||||
typeModel(_, type, _)
|
||||
) and
|
||||
(
|
||||
Specific::isPackageUsed(package)
|
||||
Specific::isTypeUsed(type)
|
||||
or
|
||||
exists(TestAllModels t)
|
||||
)
|
||||
or
|
||||
exists(string other |
|
||||
isRelevantPackage(other) and
|
||||
typeModel(package, _, other, _, _)
|
||||
exists(string other | isRelevantType(other) |
|
||||
typeModel(type, other, _)
|
||||
or
|
||||
Specific::hasImplicitTypeModel(type, other)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `package,type,path` is used in some CSV row.
|
||||
* Holds if `type,path` is used in some CSV row.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isRelevantFullPath(string package, string type, string path) {
|
||||
isRelevantPackage(package) and
|
||||
predicate isRelevantFullPath(string type, string path) {
|
||||
isRelevantType(type) and
|
||||
(
|
||||
sourceModel(package, type, path, _) or
|
||||
sinkModel(package, type, path, _) or
|
||||
summaryModel(package, type, path, _, _, _) or
|
||||
typeModel(_, _, package, type, path)
|
||||
sourceModel(type, path, _) or
|
||||
sinkModel(type, path, _) or
|
||||
summaryModel(type, path, _, _, _) or
|
||||
typeModel(_, type, path)
|
||||
)
|
||||
}
|
||||
|
||||
/** A string from a CSV row that should be parsed as an access path. */
|
||||
private class AccessPathRange extends AccessPath::Range {
|
||||
AccessPathRange() {
|
||||
isRelevantFullPath(_, _, this)
|
||||
isRelevantFullPath(_, this)
|
||||
or
|
||||
exists(string package | isRelevantPackage(package) |
|
||||
summaryModel(package, _, _, this, _, _) or
|
||||
summaryModel(package, _, _, _, this, _)
|
||||
exists(string type | isRelevantType(type) |
|
||||
summaryModel(type, _, this, _, _) or
|
||||
summaryModel(type, _, _, this, _)
|
||||
)
|
||||
or
|
||||
typeVariableModel(_, this)
|
||||
@@ -400,83 +377,73 @@ private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, A
|
||||
}
|
||||
|
||||
private class TypeModelUseEntry extends API::EntryPoint {
|
||||
private string package;
|
||||
private string type;
|
||||
|
||||
TypeModelUseEntry() {
|
||||
exists(any(TypeModel tm).getASource(package, type)) and
|
||||
this = "TypeModelUseEntry;" + package + ";" + type
|
||||
exists(any(TypeModel tm).getASource(type)) and
|
||||
this = "TypeModelUseEntry;" + type
|
||||
}
|
||||
|
||||
override DataFlow::LocalSourceNode getASource() {
|
||||
result = any(TypeModel tm).getASource(package, type)
|
||||
}
|
||||
override DataFlow::LocalSourceNode getASource() { result = any(TypeModel tm).getASource(type) }
|
||||
|
||||
API::Node getNodeForType(string package_, string type_) {
|
||||
package = package_ and type = type_ and result = this.getANode()
|
||||
}
|
||||
API::Node getNodeForType(string type_) { type = type_ and result = this.getANode() }
|
||||
}
|
||||
|
||||
private class TypeModelDefEntry extends API::EntryPoint {
|
||||
private string package;
|
||||
private string type;
|
||||
|
||||
TypeModelDefEntry() {
|
||||
exists(any(TypeModel tm).getASink(package, type)) and
|
||||
this = "TypeModelDefEntry;" + package + ";" + type
|
||||
exists(any(TypeModel tm).getASink(type)) and
|
||||
this = "TypeModelDefEntry;" + type
|
||||
}
|
||||
|
||||
override DataFlow::Node getASink() { result = any(TypeModel tm).getASink(package, type) }
|
||||
override DataFlow::Node getASink() { result = any(TypeModel tm).getASink(type) }
|
||||
|
||||
API::Node getNodeForType(string package_, string type_) {
|
||||
package = package_ and type = type_ and result = this.getANode()
|
||||
}
|
||||
API::Node getNodeForType(string type_) { type = type_ and result = this.getANode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an API node identified by the given `(package,type)` pair.
|
||||
* Gets an API node identified by the given `type`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private API::Node getNodeFromType(string package, string type) {
|
||||
exists(string package2, string type2, AccessPath path2 |
|
||||
typeModel(package, type, package2, type2, path2) and
|
||||
result = getNodeFromPath(package2, type2, path2)
|
||||
private API::Node getNodeFromType(string type) {
|
||||
exists(string type2, AccessPath path2 |
|
||||
typeModel(type, type2, path2) and
|
||||
result = getNodeFromPath(type2, path2)
|
||||
)
|
||||
or
|
||||
result = any(TypeModelUseEntry e).getNodeForType(package, type)
|
||||
result = any(TypeModelUseEntry e).getNodeForType(type)
|
||||
or
|
||||
result = any(TypeModelDefEntry e).getNodeForType(package, type)
|
||||
result = any(TypeModelDefEntry e).getNodeForType(type)
|
||||
or
|
||||
result = any(TypeModel t).getAnApiNode(package, type)
|
||||
result = any(TypeModel t).getAnApiNode(type)
|
||||
or
|
||||
result = Specific::getExtraNodeFromType(package, type)
|
||||
result = Specific::getExtraNodeFromType(type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple.
|
||||
* Gets the API node identified by the first `n` tokens of `path` in the given `(type, path)` tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private API::Node getNodeFromPath(string package, string type, AccessPath path, int n) {
|
||||
isRelevantFullPath(package, type, path) and
|
||||
private API::Node getNodeFromPath(string type, AccessPath path, int n) {
|
||||
isRelevantFullPath(type, path) and
|
||||
(
|
||||
n = 0 and
|
||||
result = getNodeFromType(package, type)
|
||||
result = getNodeFromType(type)
|
||||
or
|
||||
result = Specific::getExtraNodeFromPath(package, type, path, n)
|
||||
result = Specific::getExtraNodeFromPath(type, path, n)
|
||||
)
|
||||
or
|
||||
result = getSuccessorFromNode(getNodeFromPath(package, type, path, n - 1), path.getToken(n - 1))
|
||||
result = getSuccessorFromNode(getNodeFromPath(type, path, n - 1), path.getToken(n - 1))
|
||||
or
|
||||
// Similar to the other recursive case, but where the path may have stepped through one or more call-site filters
|
||||
result =
|
||||
getSuccessorFromInvoke(getInvocationFromPath(package, type, path, n - 1), path.getToken(n - 1))
|
||||
result = getSuccessorFromInvoke(getInvocationFromPath(type, path, n - 1), path.getToken(n - 1))
|
||||
or
|
||||
// Apply a subpath
|
||||
result =
|
||||
getNodeFromSubPath(getNodeFromPath(package, type, path, n - 1), getSubPathAt(path, n - 1))
|
||||
result = getNodeFromSubPath(getNodeFromPath(type, path, n - 1), getSubPathAt(path, n - 1))
|
||||
or
|
||||
// Apply a type step
|
||||
typeStep(getNodeFromPath(package, type, path, n), result)
|
||||
typeStep(getNodeFromPath(type, path, n), result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,15 +463,15 @@ private AccessPath getSubPathAt(AccessPath path, int n) {
|
||||
pragma[nomagic]
|
||||
private API::Node getNodeFromSubPath(API::Node base, AccessPath subPath, int n) {
|
||||
exists(AccessPath path, int k |
|
||||
base = [getNodeFromPath(_, _, path, k), getNodeFromSubPath(_, path, k)] and
|
||||
base = [getNodeFromPath(_, path, k), getNodeFromSubPath(_, path, k)] and
|
||||
subPath = getSubPathAt(path, k) and
|
||||
result = base and
|
||||
n = 0
|
||||
)
|
||||
or
|
||||
exists(string package, string type, AccessPath basePath |
|
||||
typeStepModel(package, type, basePath, subPath) and
|
||||
base = getNodeFromPath(package, type, basePath) and
|
||||
exists(string type, AccessPath basePath |
|
||||
typeStepModel(type, basePath, subPath) and
|
||||
base = getNodeFromPath(type, basePath) and
|
||||
result = base and
|
||||
n = 0
|
||||
)
|
||||
@@ -543,42 +510,40 @@ private API::Node getNodeFromSubPath(API::Node base, AccessPath subPath) {
|
||||
result = getNodeFromSubPath(base, subPath, subPath.getNumToken())
|
||||
}
|
||||
|
||||
/** Gets the node identified by the given `(package, type, path)` tuple. */
|
||||
private API::Node getNodeFromPath(string package, string type, AccessPath path) {
|
||||
result = getNodeFromPath(package, type, path, path.getNumToken())
|
||||
/** Gets the node identified by the given `(type, path)` tuple. */
|
||||
private API::Node getNodeFromPath(string type, AccessPath path) {
|
||||
result = getNodeFromPath(type, path, path.getNumToken())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStepModel(string package, string type, AccessPath basePath, AccessPath output) {
|
||||
summaryModel(package, type, basePath, "", output, "type")
|
||||
private predicate typeStepModel(string type, AccessPath basePath, AccessPath output) {
|
||||
summaryModel(type, basePath, "", output, "type")
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStep(API::Node pred, API::Node succ) {
|
||||
exists(string package, string type, AccessPath basePath, AccessPath output |
|
||||
typeStepModel(package, type, basePath, output) and
|
||||
pred = getNodeFromPath(package, type, basePath) and
|
||||
exists(string type, AccessPath basePath, AccessPath output |
|
||||
typeStepModel(type, basePath, output) and
|
||||
pred = getNodeFromPath(type, basePath) and
|
||||
succ = getNodeFromSubPath(pred, output)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an invocation identified by the given `(package, type, path)` tuple.
|
||||
* Gets an invocation identified by the given `(type, path)` tuple.
|
||||
*
|
||||
* Unlike `getNodeFromPath`, the `path` may end with one or more call-site filters.
|
||||
*/
|
||||
private Specific::InvokeNode getInvocationFromPath(
|
||||
string package, string type, AccessPath path, int n
|
||||
) {
|
||||
result = Specific::getAnInvocationOf(getNodeFromPath(package, type, path, n))
|
||||
private Specific::InvokeNode getInvocationFromPath(string type, AccessPath path, int n) {
|
||||
result = Specific::getAnInvocationOf(getNodeFromPath(type, path, n))
|
||||
or
|
||||
result = getInvocationFromPath(package, type, path, n - 1) and
|
||||
result = getInvocationFromPath(type, path, n - 1) and
|
||||
invocationMatchesCallSiteFilter(result, path.getToken(n - 1))
|
||||
}
|
||||
|
||||
/** Gets an invocation identified by the given `(package, type, path)` tuple. */
|
||||
private Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPath path) {
|
||||
result = getInvocationFromPath(package, type, path, path.getNumToken())
|
||||
/** Gets an invocation identified by the given `(type, path)` tuple. */
|
||||
private Specific::InvokeNode getInvocationFromPath(string type, AccessPath path) {
|
||||
result = getInvocationFromPath(type, path, path.getNumToken())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -631,9 +596,9 @@ module ModelOutput {
|
||||
*/
|
||||
cached
|
||||
API::Node getASourceNode(string kind) {
|
||||
exists(string package, string type, string path |
|
||||
sourceModel(package, type, path, kind) and
|
||||
result = getNodeFromPath(package, type, path)
|
||||
exists(string type, string path |
|
||||
sourceModel(type, path, kind) and
|
||||
result = getNodeFromPath(type, path)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -642,9 +607,9 @@ module ModelOutput {
|
||||
*/
|
||||
cached
|
||||
API::Node getASinkNode(string kind) {
|
||||
exists(string package, string type, string path |
|
||||
sinkModel(package, type, path, kind) and
|
||||
result = getNodeFromPath(package, type, path)
|
||||
exists(string type, string path |
|
||||
sinkModel(type, path, kind) and
|
||||
result = getNodeFromPath(type, path)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -653,32 +618,31 @@ module ModelOutput {
|
||||
*/
|
||||
cached
|
||||
predicate relevantSummaryModel(
|
||||
string package, string type, string path, string input, string output, string kind
|
||||
string type, string path, string input, string output, string kind
|
||||
) {
|
||||
isRelevantPackage(package) and
|
||||
summaryModel(package, type, path, input, output, kind)
|
||||
isRelevantType(type) and
|
||||
summaryModel(type, path, input, output, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `baseNode` is an invocation identified by the `package,type,path` part of a summary row.
|
||||
* Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row.
|
||||
*/
|
||||
cached
|
||||
predicate resolvedSummaryBase(
|
||||
string package, string type, string path, Specific::InvokeNode baseNode
|
||||
) {
|
||||
summaryModel(package, type, path, _, _, _) and
|
||||
baseNode = getInvocationFromPath(package, type, path)
|
||||
predicate resolvedSummaryBase(string type, string path, Specific::InvokeNode baseNode) {
|
||||
summaryModel(type, path, _, _, _) and
|
||||
baseNode = getInvocationFromPath(type, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
|
||||
* Holds if `node` is seen as an instance of `type` due to a type definition
|
||||
* contributed by a CSV model.
|
||||
*/
|
||||
cached
|
||||
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
|
||||
API::Node getATypeNode(string type) { result = getNodeFromType(type) }
|
||||
}
|
||||
|
||||
import Cached
|
||||
import Specific::ModelOutputSpecific
|
||||
|
||||
/**
|
||||
* Gets an error message relating to an invalid CSV row in a model.
|
||||
@@ -686,13 +650,13 @@ module ModelOutput {
|
||||
string getAWarning() {
|
||||
// Check number of columns
|
||||
exists(string row, string kind, int expectedArity, int actualArity |
|
||||
any(SourceModelCsv csv).row(row) and kind = "source" and expectedArity = 4
|
||||
any(SourceModelCsv csv).row(row) and kind = "source" and expectedArity = 3
|
||||
or
|
||||
any(SinkModelCsv csv).row(row) and kind = "sink" and expectedArity = 4
|
||||
any(SinkModelCsv csv).row(row) and kind = "sink" and expectedArity = 3
|
||||
or
|
||||
any(SummaryModelCsv csv).row(row) and kind = "summary" and expectedArity = 6
|
||||
any(SummaryModelCsv csv).row(row) and kind = "summary" and expectedArity = 5
|
||||
or
|
||||
any(TypeModelCsv csv).row(row) and kind = "type" and expectedArity = 5
|
||||
any(TypeModelCsv csv).row(row) and kind = "type" and expectedArity = 3
|
||||
or
|
||||
any(TypeVariableModelCsv csv).row(row) and kind = "type-variable" and expectedArity = 2
|
||||
|
|
||||
@@ -705,7 +669,7 @@ module ModelOutput {
|
||||
or
|
||||
// Check names and arguments of access path tokens
|
||||
exists(AccessPath path, AccessPathToken token |
|
||||
(isRelevantFullPath(_, _, path) or typeVariableModel(_, path)) and
|
||||
(isRelevantFullPath(_, path) or typeVariableModel(_, path)) and
|
||||
token = path.getToken(_)
|
||||
|
|
||||
not isValidTokenNameInIdentifyingAccessPath(token.getName()) and
|
||||
|
||||
@@ -34,30 +34,73 @@ private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSumm
|
||||
private import codeql.ruby.dataflow.internal.FlowSummaryImpl::Public
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
/**
|
||||
* Holds if models describing `package` may be relevant for the analysis of this database.
|
||||
*
|
||||
* In the context of Ruby, this is the name of a Ruby gem.
|
||||
*/
|
||||
bindingset[package]
|
||||
predicate isPackageUsed(string package) {
|
||||
// For now everything is modeled as an access path starting at any top-level, so the package name has no effect.
|
||||
//
|
||||
// We allow an arbitrary package name so that the model can record the name of the package in case it's needed in the future.
|
||||
//
|
||||
// In principle we should consider a package to be "used" if there is a transitive dependency on it, but we can only
|
||||
// reliably see the direct dependencies.
|
||||
//
|
||||
// In practice, packages try to use unique top-level module names, which mitigates the precision loss of not checking
|
||||
// the package name.
|
||||
any()
|
||||
pragma[nomagic]
|
||||
private predicate isUsedTopLevelConstant(string name) {
|
||||
exists(ConstantAccess access |
|
||||
access.getName() = name and
|
||||
not exists(access.getScopeExpr())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a Ruby-specific interpretation of the `(package, type, path)` tuple after resolving the first `n` access path tokens. */
|
||||
bindingset[package, type, path]
|
||||
API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int n) {
|
||||
// A row of form `;any;Method[foo]` should match any method named `foo`.
|
||||
exists(package) and
|
||||
bindingset[rawType]
|
||||
predicate isTypeUsed(string rawType) {
|
||||
exists(string consts |
|
||||
parseType(rawType, consts, _) and
|
||||
isUsedTopLevelConstant(consts.splitAt("::", 0))
|
||||
)
|
||||
or
|
||||
rawType = ["", "any"]
|
||||
}
|
||||
|
||||
bindingset[rawType]
|
||||
private predicate parseType(string rawType, string consts, string suffix) {
|
||||
exists(string regexp |
|
||||
regexp = "([^!]+)(!|)" and
|
||||
consts = rawType.regexpCapture(regexp, 1) and
|
||||
suffix = rawType.regexpCapture(regexp, 2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `type` can be obtained from an instance of `otherType` due to
|
||||
* language semantics modeled by `getExtraNodeFromType`.
|
||||
*/
|
||||
bindingset[otherType]
|
||||
predicate hasImplicitTypeModel(string type, string otherType) {
|
||||
// A::B! can be used to obtain A::B
|
||||
parseType(otherType, type, _)
|
||||
}
|
||||
|
||||
private predicate parseRelevantType(string rawType, string consts, string suffix) {
|
||||
isRelevantType(rawType) and
|
||||
parseType(rawType, consts, suffix)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string getConstComponent(string consts, int n) {
|
||||
parseRelevantType(_, consts, _) and
|
||||
result = consts.splitAt("::", n)
|
||||
}
|
||||
|
||||
private int getNumConstComponents(string consts) {
|
||||
result = strictcount(int n | exists(getConstComponent(consts, n)))
|
||||
}
|
||||
|
||||
private DataFlow::ConstRef getConstantFromConstPath(string consts, int n) {
|
||||
n = 1 and
|
||||
result = DataFlow::getConstant(getConstComponent(consts, 0))
|
||||
or
|
||||
result = getConstantFromConstPath(consts, n - 1).getConstant(getConstComponent(consts, n - 1))
|
||||
}
|
||||
|
||||
private DataFlow::ConstRef getConstantFromConstPath(string consts) {
|
||||
result = getConstantFromConstPath(consts, getNumConstComponents(consts))
|
||||
}
|
||||
|
||||
/** Gets a Ruby-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */
|
||||
bindingset[type, path]
|
||||
API::Node getExtraNodeFromPath(string type, AccessPath path, int n) {
|
||||
// A row of form `any;Method[foo]` should match any method named `foo`.
|
||||
type = "any" and
|
||||
n = 1 and
|
||||
exists(EntryPointFromAnyType entry |
|
||||
@@ -66,9 +109,27 @@ API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a Ruby-specific interpretation of the `(package, type)` tuple. */
|
||||
API::Node getExtraNodeFromType(string package, string type) {
|
||||
isRelevantFullPath(package, type, _) and // Allow any package name, see `isPackageUsed`.
|
||||
/** Gets a Ruby-specific interpretation of the given `type`. */
|
||||
API::Node getExtraNodeFromType(string type) {
|
||||
exists(string consts, string suffix, DataFlow::ConstRef constRef |
|
||||
parseRelevantType(type, consts, suffix) and
|
||||
constRef = getConstantFromConstPath(consts)
|
||||
|
|
||||
suffix = "!" and
|
||||
(
|
||||
result.asSource() = constRef
|
||||
or
|
||||
result.asSource() = constRef.getADescendentModule().getAnOwnModuleSelf()
|
||||
)
|
||||
or
|
||||
suffix = "" and
|
||||
(
|
||||
result.asSource() = constRef.getAMethodCall("new")
|
||||
or
|
||||
result.asSource() = constRef.getADescendentModule().getAnInstanceSelf()
|
||||
)
|
||||
)
|
||||
or
|
||||
type = "" and
|
||||
result = API::root()
|
||||
}
|
||||
@@ -78,7 +139,7 @@ API::Node getExtraNodeFromType(string package, string type) {
|
||||
* matching anywhere, and the path begins with `Method[methodName]`.
|
||||
*/
|
||||
private predicate methodMatchedByName(AccessPath path, string methodName) {
|
||||
isRelevantFullPath(_, "any", path) and
|
||||
isRelevantFullPath("any", path) and
|
||||
exists(AccessPathToken token |
|
||||
token = path.getToken(0) and
|
||||
token.getName() = "Method" and
|
||||
@@ -190,3 +251,5 @@ predicate isExtraValidTokenArgumentInIdentifyingAccessPath(string name, string a
|
||||
argument.regexpMatch("\\w+:") // keyword argument
|
||||
)
|
||||
}
|
||||
|
||||
module ModelOutputSpecific { }
|
||||
|
||||
@@ -123,33 +123,31 @@ module Pathname {
|
||||
*/
|
||||
private class PathnameTypeSummary extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package1;type1;package2;type2;path
|
||||
// type1;type2;path
|
||||
row =
|
||||
[
|
||||
// Pathname.new : Pathname
|
||||
";Pathname;;;Member[Pathname].Instance",
|
||||
// Pathname#+(path) : Pathname
|
||||
";Pathname;;Pathname;Method[+].ReturnValue",
|
||||
"Pathname;Pathname;Method[+].ReturnValue",
|
||||
// Pathname#/(path) : Pathname
|
||||
";Pathname;;Pathname;Method[/].ReturnValue",
|
||||
"Pathname;Pathname;Method[/].ReturnValue",
|
||||
// Pathname#basename(path) : Pathname
|
||||
";Pathname;;Pathname;Method[basename].ReturnValue",
|
||||
"Pathname;Pathname;Method[basename].ReturnValue",
|
||||
// Pathname#cleanpath(path) : Pathname
|
||||
";Pathname;;Pathname;Method[cleanpath].ReturnValue",
|
||||
"Pathname;Pathname;Method[cleanpath].ReturnValue",
|
||||
// Pathname#expand_path(path) : Pathname
|
||||
";Pathname;;Pathname;Method[expand_path].ReturnValue",
|
||||
"Pathname;Pathname;Method[expand_path].ReturnValue",
|
||||
// Pathname#join(path) : Pathname
|
||||
";Pathname;;Pathname;Method[join].ReturnValue",
|
||||
"Pathname;Pathname;Method[join].ReturnValue",
|
||||
// Pathname#realpath(path) : Pathname
|
||||
";Pathname;;Pathname;Method[realpath].ReturnValue",
|
||||
"Pathname;Pathname;Method[realpath].ReturnValue",
|
||||
// Pathname#relative_path_from(path) : Pathname
|
||||
";Pathname;;Pathname;Method[relative_path_from].ReturnValue",
|
||||
"Pathname;Pathname;Method[relative_path_from].ReturnValue",
|
||||
// Pathname#sub(path) : Pathname
|
||||
";Pathname;;Pathname;Method[sub].ReturnValue",
|
||||
"Pathname;Pathname;Method[sub].ReturnValue",
|
||||
// Pathname#sub_ext(path) : Pathname
|
||||
";Pathname;;Pathname;Method[sub_ext].ReturnValue",
|
||||
"Pathname;Pathname;Method[sub_ext].ReturnValue",
|
||||
// Pathname#to_path(path) : Pathname
|
||||
";Pathname;;Pathname;Method[to_path].ReturnValue",
|
||||
"Pathname;Pathname;Method[to_path].ReturnValue",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -160,31 +158,31 @@ module Pathname {
|
||||
row =
|
||||
[
|
||||
// Pathname.new(path)
|
||||
";;Member[Pathname].Method[new];Argument[0];ReturnValue;taint",
|
||||
"Pathname!;Method[new];Argument[0];ReturnValue;taint",
|
||||
// Pathname#dirname
|
||||
";Pathname;Method[dirname];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[dirname];Argument[self];ReturnValue;taint",
|
||||
// Pathname#each_filename
|
||||
";Pathname;Method[each_filename];Argument[self];Argument[block].Parameter[0];taint",
|
||||
"Pathname;Method[each_filename];Argument[self];Argument[block].Parameter[0];taint",
|
||||
// Pathname#expand_path
|
||||
";Pathname;Method[expand_path];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[expand_path];Argument[self];ReturnValue;taint",
|
||||
// Pathname#join
|
||||
";Pathname;Method[join];Argument[self,any];ReturnValue;taint",
|
||||
"Pathname;Method[join];Argument[self,any];ReturnValue;taint",
|
||||
// Pathname#parent
|
||||
";Pathname;Method[parent];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[parent];Argument[self];ReturnValue;taint",
|
||||
// Pathname#realpath
|
||||
";Pathname;Method[realpath];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[realpath];Argument[self];ReturnValue;taint",
|
||||
// Pathname#relative_path_from
|
||||
";Pathname;Method[relative_path_from];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[relative_path_from];Argument[self];ReturnValue;taint",
|
||||
// Pathname#to_path
|
||||
";Pathname;Method[to_path];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[to_path];Argument[self];ReturnValue;taint",
|
||||
// Pathname#basename
|
||||
";Pathname;Method[basename];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[basename];Argument[self];ReturnValue;taint",
|
||||
// Pathname#cleanpath
|
||||
";Pathname;Method[cleanpath];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[cleanpath];Argument[self];ReturnValue;taint",
|
||||
// Pathname#sub
|
||||
";Pathname;Method[sub];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[sub];Argument[self];ReturnValue;taint",
|
||||
// Pathname#sub_ext
|
||||
";Pathname;Method[sub_ext];Argument[self];ReturnValue;taint",
|
||||
"Pathname;Method[sub_ext];Argument[self];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
| file://:0:0:0:0 | [summary] read: argument position 0.any element in Hash[] | file://:0:0:0:0 | [summary] read: argument position 0.any element.element 1 or unknown in Hash[] |
|
||||
| file://:0:0:0:0 | parameter any of ;Pathname;Method[join] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[join] |
|
||||
| file://:0:0:0:0 | parameter position 0 of & | file://:0:0:0:0 | [summary] read: argument position 0.any element in & |
|
||||
| file://:0:0:0:0 | parameter position 0 of + | file://:0:0:0:0 | [summary] read: argument position 0.any element in + |
|
||||
| file://:0:0:0:0 | parameter position 0 of ;;Member[Pathname].Method[new] | file://:0:0:0:0 | [summary] to write: return (return) in ;;Member[Pathname].Method[new] |
|
||||
| file://:0:0:0:0 | parameter position 0 of ;;Member[Regexp].Method[escape,quote] | file://:0:0:0:0 | [summary] to write: return (return) in ;;Member[Regexp].Method[escape,quote] |
|
||||
| file://:0:0:0:0 | parameter position 0 of ActionController::Parameters#merge | file://:0:0:0:0 | [summary] to write: return (return) in ActionController::Parameters#merge |
|
||||
| file://:0:0:0:0 | parameter position 0 of ActionController::Parameters#merge! | file://:0:0:0:0 | [summary] to write: argument self in ActionController::Parameters#merge! |
|
||||
| file://:0:0:0:0 | parameter position 0 of ActionController::Parameters#merge! | file://:0:0:0:0 | [summary] to write: return (return) in ActionController::Parameters#merge! |
|
||||
@@ -17,27 +14,10 @@
|
||||
| file://:0:0:0:0 | parameter position 0 of Hash[] | file://:0:0:0:0 | [summary] read: argument position 0.any element in Hash[] |
|
||||
| file://:0:0:0:0 | parameter position 0 of String.try_convert | file://:0:0:0:0 | [summary] to write: return (return) in String.try_convert |
|
||||
| file://:0:0:0:0 | parameter position 0 of \| | file://:0:0:0:0 | [summary] read: argument position 0.any element in \| |
|
||||
| file://:0:0:0:0 | parameter position 0 of activestorage;;Member[ActiveStorage].Member[Filename].Method[new] | file://:0:0:0:0 | [summary] to write: return (return) in activestorage;;Member[ActiveStorage].Member[Filename].Method[new] |
|
||||
| file://:0:0:0:0 | parameter position 0 of activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[safe_concat] | file://:0:0:0:0 | [summary] to write: argument self in activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[safe_concat] |
|
||||
| file://:0:0:0:0 | parameter position 0 of activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[safe_concat] | file://:0:0:0:0 | [summary] to write: return (return) in activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[safe_concat] |
|
||||
| file://:0:0:0:0 | parameter position 0 of activesupport;;Member[ActionView].Member[SafeBuffer].Method[new] | file://:0:0:0:0 | [summary] to write: return (return) in activesupport;;Member[ActionView].Member[SafeBuffer].Method[new] |
|
||||
| file://:0:0:0:0 | parameter position 0.. of File.join | file://:0:0:0:0 | [summary] to write: return (return) in File.join |
|
||||
| file://:0:0:0:0 | parameter self of & | file://:0:0:0:0 | [summary] read: argument self.any element in & |
|
||||
| file://:0:0:0:0 | parameter self of * | file://:0:0:0:0 | [summary] read: argument self.any element in * |
|
||||
| file://:0:0:0:0 | parameter self of - | file://:0:0:0:0 | [summary] read: argument self.any element in - |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[basename] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[basename] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[cleanpath] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[cleanpath] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[dirname] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[dirname] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[each_filename] | file://:0:0:0:0 | [summary] to write: argument block.parameter position 0 in ;Pathname;Method[each_filename] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[existence] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[existence] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[expand_path] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[expand_path] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[join] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[join] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[parent] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[parent] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[realpath] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[realpath] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[relative_path_from] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[relative_path_from] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[sub] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[sub] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[sub_ext] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[sub_ext] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[to_path] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[to_path] |
|
||||
| file://:0:0:0:0 | parameter self of ActionController::Parameters#<various> | file://:0:0:0:0 | [summary] to write: return (return) in ActionController::Parameters#<various> |
|
||||
| file://:0:0:0:0 | parameter self of ActionController::Parameters#merge | file://:0:0:0:0 | [summary] to write: return (return) in ActionController::Parameters#merge |
|
||||
| file://:0:0:0:0 | parameter self of ActionController::Parameters#merge! | file://:0:0:0:0 | [summary] to write: argument self in ActionController::Parameters#merge! |
|
||||
@@ -45,8 +25,6 @@
|
||||
| file://:0:0:0:0 | parameter self of ActiveSupportStringTransform | file://:0:0:0:0 | [summary] to write: return (return) in ActiveSupportStringTransform |
|
||||
| file://:0:0:0:0 | parameter self of [] | file://:0:0:0:0 | [summary] to write: return (return) in [] |
|
||||
| file://:0:0:0:0 | parameter self of \| | file://:0:0:0:0 | [summary] read: argument self.any element in \| |
|
||||
| file://:0:0:0:0 | parameter self of activestorage;;Member[ActiveStorage].Member[Filename].Instance.Method[sanitized] | file://:0:0:0:0 | [summary] to write: return (return) in activestorage;;Member[ActiveStorage].Member[Filename].Instance.Method[sanitized] |
|
||||
| file://:0:0:0:0 | parameter self of activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[concat,insert,prepend,to_s,to_param] | file://:0:0:0:0 | [summary] to write: return (return) in activesupport;;Member[ActionView].Member[SafeBuffer].Instance.Method[concat,insert,prepend,to_s,to_param] |
|
||||
| file://:0:0:0:0 | parameter self of each(0) | file://:0:0:0:0 | [summary] read: argument self.any element in each(0) |
|
||||
| local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self |
|
||||
| local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) |
|
||||
|
||||
@@ -534,8 +534,8 @@ invalidSpecComponent
|
||||
| summaries.rb:150:39:150:45 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:150:39:150:45 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||
| summaries.rb:150:39:150:45 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:150:39:150:45 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||
warning
|
||||
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
|
||||
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |
|
||||
| CSV type row should have 3 columns but has 1: TooFewColumns |
|
||||
| CSV type row should have 3 columns but has 6: TooManyColumns;;Member[Foo].Instance;too;many;columns |
|
||||
| Invalid argument '0-1' in token 'Argument[0-1]' in access path: Method[foo].Argument[0-1] |
|
||||
| Invalid argument '*' in token 'Argument[*]' in access path: Method[foo].Argument[*] |
|
||||
| Invalid token 'Argument' is missing its arguments, in access path: Method[foo].Argument |
|
||||
|
||||
@@ -67,32 +67,32 @@ private class StepsFromModel extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";any;Method[set_value];Argument[0];Argument[self].Field[@value];value",
|
||||
";any;Method[get_value];Argument[self].Field[@value];ReturnValue;value",
|
||||
";;Member[Foo].Method[firstArg];Argument[0];ReturnValue;taint",
|
||||
";;Member[Foo].Method[secondArg];Argument[1];ReturnValue;taint",
|
||||
";;Member[Foo].Method[onlyWithoutBlock].WithoutBlock;Argument[0];ReturnValue;taint",
|
||||
";;Member[Foo].Method[onlyWithBlock].WithBlock;Argument[0];ReturnValue;taint",
|
||||
";;Member[Foo].Method[blockArg].Argument[block].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||
";;Member[Foo].Method[namedArg];Argument[foo:];ReturnValue;taint",
|
||||
";;Member[Foo].Method[anyArg];Argument[any];ReturnValue;taint",
|
||||
";;Member[Foo].Method[anyNamedArg];Argument[any-named];ReturnValue;taint",
|
||||
";;Member[Foo].Method[anyPositionFromOne];Argument[1..];ReturnValue;taint",
|
||||
";;Member[Foo].Method[intoNamedCallback];Argument[0];Argument[foo:].Parameter[0];taint",
|
||||
";;Member[Foo].Method[intoNamedParameter];Argument[0];Argument[0].Parameter[foo:];taint",
|
||||
";;Member[Foo].Method[startInNamedCallback].Argument[foo:].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||
";;Member[Foo].Method[startInNamedParameter].Argument[0].Parameter[foo:].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||
";;Member[Foo].Instance.Method[flowToAnyArg];Argument[0];Argument[any];taint",
|
||||
";;Member[Foo].Instance.Method[flowToSelf];Argument[0];Argument[self];taint",
|
||||
";any;Method[matchedByName];Argument[0];ReturnValue;taint",
|
||||
";any;Method[matchedByNameRcv];Argument[self];ReturnValue;taint",
|
||||
";any;Method[withElementOne];Argument[self].WithElement[1];ReturnValue;value",
|
||||
";any;Method[withExactlyElementOne];Argument[self].WithElement[1!];ReturnValue;value",
|
||||
";any;Method[withoutElementOne];Argument[self].WithoutElement[1];Argument[self];value",
|
||||
";any;Method[withoutExactlyElementOne];Argument[self].WithoutElement[1!];Argument[self];value",
|
||||
";any;Method[readElementOne];Argument[self].Element[1];ReturnValue;value",
|
||||
";any;Method[readExactlyElementOne];Argument[self].Element[1!];ReturnValue;value",
|
||||
";any;Method[withoutElementOneAndTwo];Argument[self].WithoutElement[1].WithoutElement[2].WithElement[any];Argument[self];value",
|
||||
"any;Method[set_value];Argument[0];Argument[self].Field[@value];value",
|
||||
"any;Method[get_value];Argument[self].Field[@value];ReturnValue;value",
|
||||
"Foo!;Method[firstArg];Argument[0];ReturnValue;taint",
|
||||
"Foo!;Method[secondArg];Argument[1];ReturnValue;taint",
|
||||
"Foo!;Method[onlyWithoutBlock].WithoutBlock;Argument[0];ReturnValue;taint",
|
||||
"Foo!;Method[onlyWithBlock].WithBlock;Argument[0];ReturnValue;taint",
|
||||
"Foo!;Method[blockArg].Argument[block].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||
"Foo!;Method[namedArg];Argument[foo:];ReturnValue;taint",
|
||||
"Foo!;Method[anyArg];Argument[any];ReturnValue;taint",
|
||||
"Foo!;Method[anyNamedArg];Argument[any-named];ReturnValue;taint",
|
||||
"Foo!;Method[anyPositionFromOne];Argument[1..];ReturnValue;taint",
|
||||
"Foo!;Method[intoNamedCallback];Argument[0];Argument[foo:].Parameter[0];taint",
|
||||
"Foo!;Method[intoNamedParameter];Argument[0];Argument[0].Parameter[foo:];taint",
|
||||
"Foo!;Method[startInNamedCallback].Argument[foo:].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||
"Foo!;Method[startInNamedParameter].Argument[0].Parameter[foo:].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||
"Foo;Method[flowToAnyArg];Argument[0];Argument[any];taint",
|
||||
"Foo;Method[flowToSelf];Argument[0];Argument[self];taint",
|
||||
"any;Method[matchedByName];Argument[0];ReturnValue;taint",
|
||||
"any;Method[matchedByNameRcv];Argument[self];ReturnValue;taint",
|
||||
"any;Method[withElementOne];Argument[self].WithElement[1];ReturnValue;value",
|
||||
"any;Method[withExactlyElementOne];Argument[self].WithElement[1!];ReturnValue;value",
|
||||
"any;Method[withoutElementOne];Argument[self].WithoutElement[1];Argument[self];value",
|
||||
"any;Method[withoutExactlyElementOne];Argument[self].WithoutElement[1!];Argument[self];value",
|
||||
"any;Method[readElementOne];Argument[self].Element[1];ReturnValue;value",
|
||||
"any;Method[readExactlyElementOne];Argument[self].Element[1!];ReturnValue;value",
|
||||
"any;Method[withoutElementOneAndTwo];Argument[self].WithoutElement[1].WithoutElement[2].WithElement[any];Argument[self];value",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -101,23 +101,21 @@ private class TypeFromModel extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"test;FooOrBar;;;Member[Foo].Instance", //
|
||||
"test;FooOrBar;;;Member[Bar].Instance", //
|
||||
"test;FooOrBar;test;FooOrBar;Method[next].ReturnValue",
|
||||
"~FooOrBar;Foo;", //
|
||||
"~FooOrBar;Bar;", //
|
||||
"~FooOrBar;~FooOrBar;Method[next].ReturnValue",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeFromCodeQL extends ModelInput::TypeModel {
|
||||
override DataFlow::Node getASource(string package, string type) {
|
||||
package = "test" and
|
||||
type = "FooOrBar" and
|
||||
override DataFlow::Node getASource(string type) {
|
||||
type = "~FooOrBar" and
|
||||
result.getConstantValue().getString() = "magic_string"
|
||||
}
|
||||
|
||||
override API::Node getAnApiNode(string package, string type) {
|
||||
package = "test" and
|
||||
type = "FooOrBar" and
|
||||
override API::Node getAnApiNode(string type) {
|
||||
type = "~FooOrBar" and
|
||||
result = API::getTopLevelMember("Alias").getMember(["Foo", "Bar"])
|
||||
}
|
||||
}
|
||||
@@ -126,13 +124,13 @@ private class InvalidTypeModel extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"test;TooManyColumns;;;Member[Foo].Instance;too;many;columns", //
|
||||
"test;TooFewColumns", //
|
||||
"test;X;test;Y;Method[foo].Arg[0]", //
|
||||
"test;X;test;Y;Method[foo].Argument[0-1]", //
|
||||
"test;X;test;Y;Method[foo].Argument[*]", //
|
||||
"test;X;test;Y;Method[foo].Argument", //
|
||||
"test;X;test;Y;Method[foo].Member", //
|
||||
"TooManyColumns;;Member[Foo].Instance;too;many;columns", //
|
||||
"TooFewColumns", //
|
||||
"Foo;Foo;Method[foo].Arg[0]", //
|
||||
"Foo;Foo;Method[foo].Argument[0-1]", //
|
||||
"Foo;Foo;Method[foo].Argument[*]", //
|
||||
"Foo;Foo;Method[foo].Argument", //
|
||||
"Foo;Foo;Method[foo].Member", //
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -141,12 +139,12 @@ private class SinkFromModel extends ModelInput::SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"test;FooOrBar;Method[method].Argument[0];test-sink", //
|
||||
";;Member[Foo].Method[sinkAnyArg].Argument[any];test-sink", //
|
||||
";;Member[Foo].Method[sinkAnyNamedArg].Argument[any-named];test-sink", //
|
||||
";;Member[Foo].Method[getSinks].ReturnValue.Element[any].Method[mySink].Argument[0];test-sink", //
|
||||
";;Member[Foo].Method[arraySink].Argument[0].Element[any];test-sink", //
|
||||
";;Member[Foo].Method[secondArrayElementIsSink].Argument[0].Element[1];test-sink", //
|
||||
"~FooOrBar;Method[method].Argument[0];test-sink", //
|
||||
"Foo!;Method[sinkAnyArg].Argument[any];test-sink", //
|
||||
"Foo!;Method[sinkAnyNamedArg].Argument[any-named];test-sink", //
|
||||
"Foo!;Method[getSinks].ReturnValue.Element[any].Method[mySink].Argument[0];test-sink", //
|
||||
"Foo!;Method[arraySink].Argument[0].Element[any];test-sink", //
|
||||
"Foo!;Method[secondArrayElementIsSink].Argument[0].Element[1];test-sink", //
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,7 @@ query predicate underscore(string input, string output) {
|
||||
]
|
||||
}
|
||||
|
||||
query predicate mimeTypeInstances(API::Node n) {
|
||||
n = ModelOutput::getATypeNode("actiondispatch", "Mime::Type")
|
||||
}
|
||||
query predicate mimeTypeInstances(API::Node n) { n = ModelOutput::getATypeNode("Mime::Type") }
|
||||
|
||||
query predicate mimeTypeMatchRegExpInterpretations(
|
||||
ActionDispatch::MimeTypeMatchRegExpInterpretation s
|
||||
|
||||
@@ -59,12 +59,12 @@ pathnameInstances
|
||||
| Pathname.rb:42:1:42:3 | p01 |
|
||||
| file://:0:0:0:0 | parameter position 0 of + |
|
||||
| file://:0:0:0:0 | parameter self of + |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[cleanpath] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[expand_path] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[realpath] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[relative_path_from] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[sub_ext] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[to_path] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[cleanpath] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[expand_path] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[realpath] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[relative_path_from] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[sub_ext] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[to_path] |
|
||||
| file://:0:0:0:0 | parameter self of sub |
|
||||
| file://:0:0:0:0 | parameter self of to_s |
|
||||
fileSystemAccesses
|
||||
@@ -135,12 +135,12 @@ fileNameSources
|
||||
| Pathname.rb:42:1:42:3 | p01 |
|
||||
| file://:0:0:0:0 | parameter position 0 of + |
|
||||
| file://:0:0:0:0 | parameter self of + |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[cleanpath] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[expand_path] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[realpath] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[relative_path_from] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[sub_ext] |
|
||||
| file://:0:0:0:0 | parameter self of ;Pathname;Method[to_path] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[cleanpath] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[expand_path] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[realpath] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[relative_path_from] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[sub_ext] |
|
||||
| file://:0:0:0:0 | parameter self of Pathname;Method[to_path] |
|
||||
| file://:0:0:0:0 | parameter self of sub |
|
||||
| file://:0:0:0:0 | parameter self of to_s |
|
||||
fileSystemReadAccesses
|
||||
|
||||
Reference in New Issue
Block a user