mirror of
https://github.com/github/codeql.git
synced 2025-12-19 18:33:16 +01:00
89 lines
2.9 KiB
Plaintext
89 lines
2.9 KiB
Plaintext
import codeql.ruby.AST
|
|
import codeql.ruby.DataFlow
|
|
import TestUtilities.InlineExpectationsTest
|
|
import codeql.ruby.ApiGraphs
|
|
|
|
class CustomEntryPointCall extends API::EntryPoint {
|
|
CustomEntryPointCall() { this = "CustomEntryPointCall" }
|
|
|
|
override DataFlow::CallNode getACall() { result.getMethodName() = "customEntryPointCall" }
|
|
}
|
|
|
|
class CustomEntryPointUse extends API::EntryPoint {
|
|
CustomEntryPointUse() { this = "CustomEntryPointUse" }
|
|
|
|
override DataFlow::LocalSourceNode getASource() {
|
|
result.(DataFlow::CallNode).getMethodName() = "customEntryPointUse"
|
|
}
|
|
}
|
|
|
|
class ApiUseTest extends InlineExpectationsTest {
|
|
ApiUseTest() { this = "ApiUseTest" }
|
|
|
|
override string getARelevantTag() { result = ["use", "def", "call"] }
|
|
|
|
private predicate relevantNode(API::Node a, DataFlow::Node n, Location l, string tag) {
|
|
l = n.getLocation() and
|
|
(
|
|
tag = "use" and
|
|
n = a.getAValueReachableFromSource()
|
|
or
|
|
tag = "def" and
|
|
n = a.asSink()
|
|
or
|
|
tag = "call" and
|
|
n = a.(API::MethodAccessNode).getCallNode()
|
|
)
|
|
}
|
|
|
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
tag = "use" and // def tags are always optional
|
|
exists(DataFlow::Node n | relevantNode(_, n, location, tag) |
|
|
// Only report the longest path on this line:
|
|
value =
|
|
max(API::Node a2, Location l2, DataFlow::Node n2 |
|
|
relevantNode(a2, n2, l2, tag) and
|
|
l2.getFile() = location.getFile() and
|
|
l2.getStartLine() = location.getStartLine()
|
|
|
|
|
a2.getPath()
|
|
order by
|
|
size(n2.asExpr().getExpr()), a2.getPath().length() desc, a2.getPath() desc
|
|
) and
|
|
element = n.toString()
|
|
)
|
|
}
|
|
|
|
// We also permit optional annotations for any other path on the line.
|
|
// This is used to test subclass paths, which typically have a shorter canonical path.
|
|
override predicate hasOptionalResult(Location location, string element, string tag, string value) {
|
|
exists(API::Node a, DataFlow::Node n | relevantNode(a, n, location, tag) |
|
|
element = n.toString() and
|
|
value = getAPath(a, _)
|
|
)
|
|
}
|
|
}
|
|
|
|
private int size(AstNode n) { not n instanceof StmtSequence and result = count(n.getAChild*()) }
|
|
|
|
/**
|
|
* Gets a path of the given `length` from the root to the given node.
|
|
* This is a copy of `API::getAPath()` without the restriction on path length,
|
|
* which would otherwise rule out paths involving `getASubclass()`.
|
|
*/
|
|
string getAPath(API::Node node, int length) {
|
|
node instanceof API::Root and
|
|
length = 0 and
|
|
result = ""
|
|
or
|
|
exists(API::Node pred, API::Label::ApiLabel lbl, string predpath |
|
|
pred.getASuccessor(lbl) = node and
|
|
predpath = getAPath(pred, length - 1) and
|
|
exists(string dot | if length = 1 then dot = "" else dot = "." |
|
|
result = predpath + dot + lbl and
|
|
// avoid producing strings longer than 1MB
|
|
result.length() < 1000 * 1000
|
|
)
|
|
)
|
|
}
|