Skip to content

Commit 25d64a7

Browse files
authored
Merge pull request #7930 from erik-krogh/rbApiIpa
RB: convert the ruby ApiGraphs to use IPA labels
2 parents 678645b + 5a39708 commit 25d64a7

File tree

2 files changed

+143
-54
lines changed

2 files changed

+143
-54
lines changed

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 142 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,13 @@ module API {
171171
* Gets a node such that there is an edge in the API graph between this node and the other
172172
* one, and that edge is labeled with `lbl`.
173173
*/
174-
Node getASuccessor(string lbl) { Impl::edge(this, lbl, result) }
174+
Node getASuccessor(Label::ApiLabel lbl) { Impl::edge(this, lbl, result) }
175175

176176
/**
177177
* Gets a node such that there is an edge in the API graph between that other node and
178178
* this one, and that edge is labeled with `lbl`
179179
*/
180-
Node getAPredecessor(string lbl) { this = result.getASuccessor(lbl) }
180+
Node getAPredecessor(Label::ApiLabel lbl) { this = result.getASuccessor(lbl) }
181181

182182
/**
183183
* Gets a node such that there is an edge in the API graph between this node and the other
@@ -225,9 +225,8 @@ module API {
225225
length = 0 and
226226
result = ""
227227
or
228-
exists(Node pred, string lbl, string predpath |
228+
exists(Node pred, Label::ApiLabel lbl, string predpath |
229229
Impl::edge(pred, lbl, this) and
230-
lbl != "" and
231230
predpath = pred.getAPath(length - 1) and
232231
exists(string dot | if length = 1 then dot = "" else dot = "." |
233232
result = predpath + dot + lbl and
@@ -328,7 +327,7 @@ module API {
328327
* node labeled `lbl` in the API graph.
329328
*/
330329
pragma[nomagic]
331-
private predicate useRoot(string lbl, DataFlow::Node ref) {
330+
private predicate useRoot(Label::ApiLabel lbl, DataFlow::Node ref) {
332331
exists(string name, ConstantReadAccess read |
333332
read = ref.asExpr().getExpr() and
334333
lbl = Label::member(read.getName())
@@ -345,7 +344,7 @@ module API {
345344
* Holds if `ref` is a use of a node that should have an incoming edge labeled `lbl`,
346345
* from a use node that flows to `node`.
347346
*/
348-
private predicate useStep(string lbl, DataFlow::Node node, DataFlow::Node ref) {
347+
private predicate useStep(Label::ApiLabel lbl, DataFlow::Node node, DataFlow::Node ref) {
349348
// // Referring to an attribute on a node that is a use of `base`:
350349
// pred = `Rails` part of `Rails::Whatever`
351350
// lbl = `Whatever`
@@ -433,7 +432,7 @@ module API {
433432
/** Gets a data flow node that flows to the RHS of a def-node. */
434433
private DataFlow::LocalSourceNode defCand() { result = defCand(TypeBackTracker::end()) }
435434

436-
private string getLabelFromArgumentPosition(DataFlowDispatch::ArgumentPosition pos) {
435+
private Label::ApiLabel getLabelFromArgumentPosition(DataFlowDispatch::ArgumentPosition pos) {
437436
exists(int n |
438437
pos.isPositional(n) and
439438
result = Label::parameter(n)
@@ -448,7 +447,7 @@ module API {
448447
result = Label::blockParameter()
449448
}
450449

451-
private string getLabelFromParameterPosition(DataFlowDispatch::ParameterPosition pos) {
450+
private Label::ApiLabel getLabelFromParameterPosition(DataFlowDispatch::ParameterPosition pos) {
452451
exists(int n |
453452
pos.isPositional(n) and
454453
result = Label::parameter(n)
@@ -468,7 +467,7 @@ module API {
468467
*/
469468
pragma[nomagic]
470469
private predicate argumentStep(
471-
string lbl, DataFlow::CallNode call, DataFlowPrivate::ArgumentNode argument
470+
Label::ApiLabel lbl, DataFlow::CallNode call, DataFlowPrivate::ArgumentNode argument
472471
) {
473472
exists(DataFlowDispatch::ArgumentPosition argPos |
474473
argument.sourceArgumentOf(call.asExpr(), argPos) and
@@ -481,7 +480,7 @@ module API {
481480
*/
482481
pragma[nomagic]
483482
private predicate parameterStep(
484-
string lbl, DataFlow::Node callable, DataFlowPrivate::ParameterNodeImpl paramNode
483+
Label::ApiLabel lbl, DataFlow::Node callable, DataFlowPrivate::ParameterNodeImpl paramNode
485484
) {
486485
exists(DataFlowDispatch::ParameterPosition paramPos |
487486
paramNode.isSourceParameterOf(callable.asExpr().getExpr(), paramPos) and
@@ -541,7 +540,7 @@ module API {
541540
* Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`.
542541
*/
543542
cached
544-
predicate edge(TApiNode pred, string lbl, TApiNode succ) {
543+
predicate edge(TApiNode pred, Label::ApiLabel lbl, TApiNode succ) {
545544
/* Every node that is a use of an API component is itself added to the API graph. */
546545
exists(DataFlow::LocalSourceNode ref | succ = MkUse(ref) |
547546
pred = MkRoot() and
@@ -601,49 +600,140 @@ module API {
601600
/** Gets the shortest distance from the root to `nd` in the API graph. */
602601
cached
603602
int distanceFromRoot(TApiNode nd) = shortestDistances(MkRoot/0, edge/2)(_, nd, result)
604-
}
605-
}
606603

607-
private module Label {
608-
/** Gets the `member` edge label for member `m`. */
609-
bindingset[m]
610-
bindingset[result]
611-
string member(string m) { result = "getMember(\"" + m + "\")" }
612-
613-
/** Gets the `member` edge label for the unknown member. */
614-
string unknownMember() { result = "getUnknownMember()" }
615-
616-
/** Gets the `method` edge label. */
617-
bindingset[m]
618-
bindingset[result]
619-
string method(string m) { result = "getMethod(\"" + m + "\")" }
620-
621-
/** Gets the `return` edge label. */
622-
string return() { result = "getReturn()" }
623-
624-
string subclass() { result = "getASubclass()" }
625-
626-
/** Gets the label representing the given keword argument/parameter. */
627-
bindingset[name]
628-
bindingset[result]
629-
string keywordParameter(string name) { result = "getKeywordParameter(\"" + name + "\")" }
630-
631-
/** Gets the label representing the `n`th positional argument/parameter. */
632-
bindingset[n]
633-
bindingset[result]
634-
string parameter(int n) {
635-
exists(string s |
636-
result = parameterByStr(s) and
637-
n = s.toInt() and
638-
s = n.toString()
639-
)
604+
/** All the possible labels in the API graph. */
605+
cached
606+
newtype TLabel =
607+
MkLabelMember(string member) { member = any(ConstantReadAccess a).getName() } or
608+
MkLabelUnknownMember() or
609+
MkLabelMethod(string m) { m = any(DataFlow::CallNode c).getMethodName() } or
610+
MkLabelReturn() or
611+
MkLabelSubclass() or
612+
MkLabelKeywordParameter(string name) {
613+
any(DataFlowDispatch::ArgumentPosition arg).isKeyword(name)
614+
or
615+
any(DataFlowDispatch::ParameterPosition arg).isKeyword(name)
616+
} or
617+
MkLabelParameter(int n) {
618+
any(DataFlowDispatch::ArgumentPosition c).isPositional(n)
619+
or
620+
any(DataFlowDispatch::ParameterPosition c).isPositional(n)
621+
} or
622+
MkLabelBlockParameter()
640623
}
641624

642-
/** Gets the label representing the `n`th positional argument/parameter. */
643-
bindingset[n]
644-
bindingset[result]
645-
string parameterByStr(string n) { result = "getParameter(" + n + ")" }
625+
/** Provides classes modeling the various edges (labels) in the API graph. */
626+
module Label {
627+
/** A label in the API-graph */
628+
class ApiLabel extends Impl::TLabel {
629+
/** Gets a string representation of this label. */
630+
string toString() { result = "???" }
631+
}
632+
633+
private import LabelImpl
634+
635+
private module LabelImpl {
636+
private import Impl
637+
638+
/** A label for a member, for example a constant. */
639+
class LabelMember extends ApiLabel {
640+
private string member;
641+
642+
LabelMember() { this = MkLabelMember(member) }
643+
644+
/** Gets the member name associated with this label. */
645+
string getMember() { result = member }
646+
647+
override string toString() { result = "getMember(\"" + member + "\")" }
648+
}
649+
650+
/** A label for a member with an unknown name. */
651+
class LabelUnknownMember extends ApiLabel {
652+
LabelUnknownMember() { this = MkLabelUnknownMember() }
653+
654+
override string toString() { result = "getUnknownMember()" }
655+
}
656+
657+
/** A label for a method. */
658+
class LabelMethod extends ApiLabel {
659+
private string method;
660+
661+
LabelMethod() { this = MkLabelMethod(method) }
662+
663+
/** Gets the method name associated with this label. */
664+
string getMethod() { result = method }
665+
666+
override string toString() { result = "getMethod(\"" + method + "\")" }
667+
}
668+
669+
/** A label for the return value of a method. */
670+
class LabelReturn extends ApiLabel {
671+
LabelReturn() { this = MkLabelReturn() }
672+
673+
override string toString() { result = "getReturn()" }
674+
}
675+
676+
/** A label for the subclass relationship. */
677+
class LabelSubclass extends ApiLabel {
678+
LabelSubclass() { this = MkLabelSubclass() }
646679

647-
/** Gets the label representing the block argument/parameter. */
648-
string blockParameter() { result = "getBlock()" }
680+
override string toString() { result = "getASubclass()" }
681+
}
682+
683+
/** A label for a keyword parameter. */
684+
class LabelKeywordParameter extends ApiLabel {
685+
private string name;
686+
687+
LabelKeywordParameter() { this = MkLabelKeywordParameter(name) }
688+
689+
/** Gets the name of the keyword parameter associated with this label. */
690+
string getName() { result = name }
691+
692+
override string toString() { result = "getKeywordParameter(\"" + name + "\")" }
693+
}
694+
695+
/** A label for a parameter. */
696+
class LabelParameter extends ApiLabel {
697+
private int n;
698+
699+
LabelParameter() { this = MkLabelParameter(n) }
700+
701+
/** Gets the parameter number associated with this label. */
702+
int getIndex() { result = n }
703+
704+
override string toString() { result = "getParameter(" + n + ")" }
705+
}
706+
707+
/** A label for a block parameter. */
708+
class LabelBlockParameter extends ApiLabel {
709+
LabelBlockParameter() { this = MkLabelBlockParameter() }
710+
711+
override string toString() { result = "getBlock()" }
712+
}
713+
}
714+
715+
/** Gets the `member` edge label for member `m`. */
716+
LabelMember member(string m) { result.getMember() = m }
717+
718+
/** Gets the `member` edge label for the unknown member. */
719+
LabelUnknownMember unknownMember() { any() }
720+
721+
/** Gets the `method` edge label. */
722+
LabelMethod method(string m) { result.getMethod() = m }
723+
724+
/** Gets the `return` edge label. */
725+
LabelReturn return() { any() }
726+
727+
/** Gets the `subclass` edge label. */
728+
LabelSubclass subclass() { any() }
729+
730+
/** Gets the label representing the given keword argument/parameter. */
731+
LabelKeywordParameter keywordParameter(string name) { result.getName() = name }
732+
733+
/** Gets the label representing the `n`th positional argument/parameter. */
734+
LabelParameter parameter(int n) { result.getIndex() = n }
735+
736+
/** Gets the label representing the block argument/parameter. */
737+
LabelBlockParameter blockParameter() { any() }
738+
}
649739
}

ruby/ql/test/library-tests/dataflow/api-graphs/use.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ string getAPath(API::Node node, int length) {
5959
length = 0 and
6060
result = ""
6161
or
62-
exists(API::Node pred, string lbl, string predpath |
62+
exists(API::Node pred, API::Label::ApiLabel lbl, string predpath |
6363
pred.getASuccessor(lbl) = node and
64-
lbl != "" and
6564
predpath = getAPath(pred, length - 1) and
6665
exists(string dot | if length = 1 then dot = "" else dot = "." |
6766
result = predpath + dot + lbl and

0 commit comments

Comments
 (0)