mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
JS: Add flow summaries for core methods
This commit is contained in:
@@ -6,6 +6,7 @@ private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
|
||||
private import semmle.javascript.dataflow.internal.Contents::Private
|
||||
private import semmle.javascript.dataflow.internal.VariableCapture
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.javascript.internal.flow_summaries.AllFlowSummaries
|
||||
private import sharedlib.FlowSummaryImpl as FlowSummaryImpl
|
||||
|
||||
private class Node = DataFlow::Node;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
private import AmbiguousCoreMethods
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Contains flow summaries for methods with a name that can found on more than one of the core types: Array, String, Map, Set, Promise.
|
||||
*
|
||||
* This is an overview of the ambiguous methods and the classes that contain them (not all of these require a flow summary):
|
||||
* ```
|
||||
* at: String, Array
|
||||
* concat: String, Array
|
||||
* includes: String, Array
|
||||
* indexOf: String, Array
|
||||
* lastIndexOf: String, Array
|
||||
* slice: String, Array
|
||||
* entries: Array, Map, Set
|
||||
* forEach: Array, Map, Set
|
||||
* keys: Array, Map, Set
|
||||
* values: Array, Map, Set
|
||||
* clear: Map, Set
|
||||
* delete: Map, Set
|
||||
* has: Map, Set
|
||||
* ```
|
||||
*
|
||||
* (Promise is absent in the table above as there currently are no name clashes with Promise methods)
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
private import FlowSummaryUtil
|
||||
|
||||
class At extends SummarizedCallable {
|
||||
At() { this = "Array#at / String#at" }
|
||||
|
||||
override InstanceCall getACallSimple() { result.getMethodName() = "at" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
input = "Argument[this].ArrayElement" and
|
||||
output = "ReturnValue"
|
||||
//
|
||||
// There is no flow for String#at since we currently consider single-character extraction to be too restrictive
|
||||
}
|
||||
}
|
||||
|
||||
class Concat extends SummarizedCallable {
|
||||
Concat() { this = "Array#concat / String#concat" }
|
||||
|
||||
override InstanceCall getACallSimple() { result.getMethodName() = "concat" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
input = "Argument[this,0..].ArrayElement" and
|
||||
output = "ReturnValue.ArrayElement"
|
||||
or
|
||||
preservesValue = false and
|
||||
input = "Argument[this,0..]" and
|
||||
output = "ReturnValue"
|
||||
}
|
||||
}
|
||||
|
||||
class Slice extends SummarizedCallable {
|
||||
Slice() { this = "Array#slice / String#slice" }
|
||||
|
||||
override InstanceCall getACallSimple() { result.getMethodName() = "slice" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
input = "Argument[this].ArrayElement" and
|
||||
output = "ReturnValue.ArrayElement"
|
||||
or
|
||||
preservesValue = false and
|
||||
input = "Argument[this]" and
|
||||
output = "ReturnValue"
|
||||
}
|
||||
}
|
||||
|
||||
class Entries extends SummarizedCallable {
|
||||
Entries() { this = "Array#entries / Map#entries / Set#entries" }
|
||||
|
||||
override InstanceCall getACall() {
|
||||
result.getMethodName() = "entries" and
|
||||
result.getNumArgument() = 0
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
(
|
||||
input = "Argument[this]." + ["MapKey", "SetElement"] and
|
||||
output = "ReturnValue.IteratorElement.Member[0]"
|
||||
or
|
||||
input = "Argument[this]." + ["ArrayElement", "SetElement", "MapValue"] and
|
||||
output = "ReturnValue.IteratorElement.Member[1]"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ForEach extends SummarizedCallable {
|
||||
ForEach() { this = "Array#forEach / Map#forEach / Set#forEach" }
|
||||
|
||||
override InstanceCall getACallSimple() { result.getMethodName() = "forEach" }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
/*
|
||||
* array.forEach(callbackfn, thisArg)
|
||||
* callbackfn(value, index, array)
|
||||
*/
|
||||
|
||||
(
|
||||
input = "Argument[this]." + ["ArrayElement", "SetElement", "MapValue"] and
|
||||
output = "Argument[0].Parameter[0]"
|
||||
or
|
||||
input = "Argument[this]." + ["MapKey", "SetElement"] and
|
||||
output = "Argument[0].Parameter[1]"
|
||||
or
|
||||
input = "Argument[this]" and
|
||||
output = "Argument[0].Parameter[2]" // object being iterated over
|
||||
or
|
||||
input = "Argument[1]" and // thisArg
|
||||
output = "Argument[0].Parameter[this]"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Keys extends SummarizedCallable {
|
||||
Keys() { this = "Array#keys / Map#keys / Set#keys" }
|
||||
|
||||
override InstanceCall getACallSimple() {
|
||||
result.getMethodName() = "keys" and
|
||||
result.getNumArgument() = 0
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
input = "Argument[this]." + ["MapKey", "SetElement"] and
|
||||
output = "ReturnValue.IteratorElement"
|
||||
}
|
||||
}
|
||||
|
||||
class Values extends SummarizedCallable {
|
||||
Values() { this = "Array#values / Map#values / Set#values" }
|
||||
|
||||
override InstanceCall getACallSimple() {
|
||||
result.getMethodName() = "values" and
|
||||
result.getNumArgument() = 0
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = true and
|
||||
input = "Argument[this]." + ["ArrayElement", "SetElement", "MapValue"] and
|
||||
output = "ReturnValue.IteratorElement"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
private import semmle.javascript.dataflow.internal.Contents::Private
|
||||
|
||||
/**
|
||||
* A method call or a reflective invocation (`call` or `apply`) that takes a receiver.
|
||||
*
|
||||
* Note that `DataFlow::MethodCallNode` does not include reflective invocation.
|
||||
*/
|
||||
class InstanceCall extends DataFlow::CallNode {
|
||||
InstanceCall() { exists(this.getReceiver()) }
|
||||
|
||||
/** Gets the name of method being invoked */
|
||||
string getMethodName() { result = this.getCalleeName() }
|
||||
}
|
||||
Reference in New Issue
Block a user