Skip to content

Commit 3b5ff73

Browse files
committed
JS: Introduce API::InvokeNode to simplify reasoning about calls
1 parent 2cf10a7 commit 3b5ff73

File tree

1 file changed

+59
-3
lines changed

1 file changed

+59
-3
lines changed

javascript/ql/src/semmle/javascript/ApiGraphs.qll

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,17 @@ module API {
5454
/**
5555
* Gets a call to the function represented by this API component.
5656
*/
57-
DataFlow::CallNode getACall() { result = getReturn().getAnImmediateUse() }
57+
CallNode getACall() { result = getReturn().getAnImmediateUse() }
5858

5959
/**
6060
* Gets a `new` call to the function represented by this API component.
6161
*/
62-
DataFlow::NewNode getAnInstantiation() { result = getInstance().getAnImmediateUse() }
62+
NewNode getAnInstantiation() { result = getInstance().getAnImmediateUse() }
6363

6464
/**
6565
* Gets an invocation (with our without `new`) to the function represented by this API component.
6666
*/
67-
DataFlow::InvokeNode getAnInvocation() { result = getACall() or result = getAnInstantiation() }
67+
InvokeNode getAnInvocation() { result = getACall() or result = getAnInstantiation() }
6868

6969
/**
7070
* Gets a data-flow node corresponding to the right-hand side of a definition of the API
@@ -114,11 +114,17 @@ module API {
114114
* For example, if this node represents a use of some class `A`, then there might be a node
115115
* representing instances of `A`, typically corresponding to expressions `new A()` at the
116116
* source level.
117+
*
118+
* This predicate may have multiple results when there are multiple constructor calls invoking this API component.
119+
* Consider using `getAnInstantiation()` if there is a need to distingiush between individual constructor calls.
117120
*/
118121
Node getInstance() { result = getASuccessor(Label::instance()) }
119122

120123
/**
121124
* Gets a node representing the `i`th parameter of the function represented by this node.
125+
*
126+
* This predicate may have multiple results when there are multiple invocations of this API component.
127+
* Consider using `getAnInvocation()` if there is a need to distingiush between individual calls.
122128
*/
123129
bindingset[i]
124130
Node getParameter(int i) { result = getASuccessor(Label::parameter(i)) }
@@ -133,6 +139,9 @@ module API {
133139

134140
/**
135141
* Gets a node representing the last parameter of the function represented by this node.
142+
*
143+
* This predicate may have multiple results when there are multiple invocations of this API component.
144+
* Consider using `getAnInvocation()` if there is a need to distingiush between individual calls.
136145
*/
137146
Node getLastParameter() { result = getParameter(getNumParameter() - 1) }
138147

@@ -144,6 +153,10 @@ module API {
144153
/**
145154
* Gets a node representing a parameter or the receiver of the function represented by this
146155
* node.
156+
*
157+
* This predicate may result in a mix of parameters from different call sites in cases where
158+
* there are multiple invocations of this API component.
159+
* Consider using `getAnInvocation()` if there is a need to distingiush between individual calls.
147160
*/
148161
Node getAParameter() {
149162
result = getASuccessor(Label::parameterByStringIndex(_)) or
@@ -152,6 +165,9 @@ module API {
152165

153166
/**
154167
* Gets a node representing the result of the function represented by this node.
168+
*
169+
* This predicate may have multiple results when there are multiple invocations of this API component.
170+
* Consider using `getACall()` if there is a need to distingiush between individual calls.
155171
*/
156172
Node getReturn() { result = getASuccessor(Label::return()) }
157173

@@ -787,6 +803,46 @@ module API {
787803
}
788804

789805
import Label as EdgeLabel
806+
807+
/**
808+
* An `InvokeNode` that is connected to the API graph.
809+
*
810+
* Can be used to reason about calls to an external API in which the correlation between
811+
* parameters and/or return values must be retained.
812+
*
813+
* The member predicates `getParameter`, `getReturn`, and `getInstance` mimic the corresponding
814+
* predicates from `API::Node`. These are guaranteed to exist and be unique to this call.
815+
*/
816+
class InvokeNode extends DataFlow::InvokeNode {
817+
API::Node callee;
818+
819+
InvokeNode() { this = callee.getReturn().getAnImmediateUse() or this = callee.getInstance().getAnImmediateUse() }
820+
821+
/** Gets the API node for the `i`th parameter of this invocation. */
822+
Node getParameter(int i) {
823+
result = callee.getParameter(i) and
824+
result.getARhs() = getArgument(i)
825+
}
826+
827+
/** Gets the API node a parameter of this invocation. */
828+
Node getAParameter() {
829+
result = getParameter(_)
830+
}
831+
832+
/** Gets the API node for the return value of this call. */
833+
Node getReturn() { result.getAnImmediateUse() = this }
834+
835+
/** Gets the API node for the object constructed by this invocation. */
836+
Node getInstance() { result.getAnImmediateUse() = this }
837+
}
838+
839+
/** A call connected to the API graph. */
840+
class CallNode extends InvokeNode, DataFlow::CallNode {
841+
}
842+
843+
/** A `new` call connected to the API graph. */
844+
class NewNode extends InvokeNode, DataFlow::NewNode {
845+
}
790846
}
791847

792848
private module Label {

0 commit comments

Comments
 (0)