Skip to content

Commit 9739929

Browse files
committed
convert the ruby ApiGraphs to use IPA labels
1 parent efed21b commit 9739929

File tree

2 files changed

+138
-55
lines changed

2 files changed

+138
-55
lines changed

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

Lines changed: 137 additions & 53 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
@@ -306,7 +305,7 @@ module API {
306305
* shortest length.
307306
*/
308307
cached
309-
private module Impl {
308+
module Impl {
310309
cached
311310
newtype TApiNode =
312311
/** The root of the API graph. */
@@ -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
@@ -602,48 +601,133 @@ module API {
602601
cached
603602
int distanceFromRoot(TApiNode nd) = shortestDistances(MkRoot/0, edge/2)(_, nd, result)
604603
}
605-
}
606604

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-
)
640-
}
605+
module Label {
606+
/** A label in the API-graph */
607+
class ApiLabel extends TLabel {
608+
/** Gets a string representation of this label. */
609+
string toString() { result = "???" }
610+
}
611+
612+
private import LabelImpl
613+
614+
private module LabelImpl {
615+
newtype TLabel =
616+
MkLabelMember(string member) { member = any(ConstantReadAccess a).getName() } or
617+
MkLabelUnknownMember() or
618+
MkLabelMethod(string m) { m = any(DataFlow::CallNode c).getMethodName() } or
619+
MkLabelReturn() or
620+
MkLabelSubclass() or
621+
MkLabelKeywordParameter(string name) {
622+
any(DataFlowDispatch::ArgumentPosition arg).isKeyword(name)
623+
or
624+
any(DataFlowDispatch::ParameterPosition arg).isKeyword(name)
625+
} or
626+
MkLabelParameter(int n) {
627+
any(DataFlowDispatch::ArgumentPosition c).isPositional(n)
628+
or
629+
any(DataFlowDispatch::ParameterPosition c).isPositional(n)
630+
} or
631+
MkLabelBlockParameter()
632+
633+
/** A label for the member named `prop`. */
634+
class LabelMember extends ApiLabel {
635+
string member;
636+
637+
LabelMember() { this = MkLabelMember(member) }
638+
639+
/** Gets the property associated with this label. */
640+
string getMember() { result = member }
641+
642+
override string toString() { result = "getMember(\"" + member + "\")" }
643+
}
644+
645+
/** A label for a member with an unknown name. */
646+
class LabelUnknownMember extends ApiLabel {
647+
LabelUnknownMember() { this = MkLabelUnknownMember() }
648+
649+
override string toString() { result = "getUnknownMember()" }
650+
}
651+
652+
/** A label for the method named `method`. */
653+
class LabelMethod extends ApiLabel {
654+
string method;
655+
656+
LabelMethod() { this = MkLabelMethod(method) }
657+
658+
/** Gets the method name associated with this label. */
659+
string getMethod() { result = method }
660+
661+
override string toString() { result = "getMethod(\"" + method + "\")" }
662+
}
663+
664+
/** A label for the return value of a method. */
665+
class LabelReturn extends ApiLabel {
666+
LabelReturn() { this = MkLabelReturn() }
667+
668+
override string toString() { result = "getReturn()" }
669+
}
670+
671+
/** A label for the subclass relationship. */
672+
class LabelSubclass extends ApiLabel {
673+
LabelSubclass() { this = MkLabelSubclass() }
641674

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 + ")" }
675+
override string toString() { result = "getASubclass()" }
676+
}
646677

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

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)