codeql-development-mcp-server 2.24.1-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +178 -0
- package/README.md +113 -0
- package/dist/codeql-development-mcp-server.js +9474 -0
- package/dist/codeql-development-mcp-server.js.map +7 -0
- package/package.json +101 -0
- package/ql/README.md +57 -0
- package/ql/actions/tools/src/PrintAST/PrintAST.ql +40 -0
- package/ql/actions/tools/src/PrintCFG/PrintCFG.md +53 -0
- package/ql/actions/tools/src/PrintCFG/PrintCFG.ql +23 -0
- package/ql/actions/tools/src/codeql-pack.lock.yml +32 -0
- package/ql/actions/tools/src/codeql-pack.yml +6 -0
- package/ql/cpp/tools/src/CallGraphFrom/CallGraphFrom.ql +55 -0
- package/ql/cpp/tools/src/CallGraphTo/CallGraphTo.ql +55 -0
- package/ql/cpp/tools/src/PrintAST/PrintAST.ql +57 -0
- package/ql/cpp/tools/src/PrintCFG/PrintCFG.md +56 -0
- package/ql/cpp/tools/src/PrintCFG/PrintCFG.ql +22 -0
- package/ql/cpp/tools/src/codeql-pack.lock.yml +28 -0
- package/ql/cpp/tools/src/codeql-pack.yml +6 -0
- package/ql/csharp/tools/src/CallGraphFrom/CallGraphFrom.ql +50 -0
- package/ql/csharp/tools/src/CallGraphTo/CallGraphTo.ql +50 -0
- package/ql/csharp/tools/src/PrintAST/PrintAST.ql +57 -0
- package/ql/csharp/tools/src/PrintCFG/PrintCFG.md +55 -0
- package/ql/csharp/tools/src/PrintCFG/PrintCFG.ql +22 -0
- package/ql/csharp/tools/src/codeql-pack.lock.yml +24 -0
- package/ql/csharp/tools/src/codeql-pack.yml +6 -0
- package/ql/go/tools/src/CallGraphFrom/CallGraphFrom.ql +39 -0
- package/ql/go/tools/src/CallGraphTo/CallGraphTo.ql +47 -0
- package/ql/go/tools/src/PrintAST/PrintAST.ql +58 -0
- package/ql/go/tools/src/PrintCFG/PrintCFG.md +55 -0
- package/ql/go/tools/src/PrintCFG/PrintCFG.ql +22 -0
- package/ql/go/tools/src/codeql-pack.lock.yml +24 -0
- package/ql/go/tools/src/codeql-pack.yml +6 -0
- package/ql/java/tools/src/CallGraphFrom/CallGraphFrom.ql +50 -0
- package/ql/java/tools/src/CallGraphTo/CallGraphTo.ql +50 -0
- package/ql/java/tools/src/PrintAST/PrintAST.ql +57 -0
- package/ql/java/tools/src/PrintCFG/PrintCFG.md +55 -0
- package/ql/java/tools/src/PrintCFG/PrintCFG.ql +35 -0
- package/ql/java/tools/src/codeql-pack.lock.yml +32 -0
- package/ql/java/tools/src/codeql-pack.yml +6 -0
- package/ql/javascript/tools/src/CallGraphFrom/CallGraphFrom.ql +49 -0
- package/ql/javascript/tools/src/CallGraphTo/CallGraphTo.ql +47 -0
- package/ql/javascript/tools/src/PrintAST/PrintAST.ql +60 -0
- package/ql/javascript/tools/src/PrintCFG/PrintCFG.md +57 -0
- package/ql/javascript/tools/src/PrintCFG/PrintCFG.ql +21 -0
- package/ql/javascript/tools/src/codeql-pack.lock.yml +30 -0
- package/ql/javascript/tools/src/codeql-pack.yml +6 -0
- package/ql/python/tools/src/CallGraphFrom/CallGraphFrom.ql +49 -0
- package/ql/python/tools/src/CallGraphTo/CallGraphTo.ql +47 -0
- package/ql/python/tools/src/PrintAST/PrintAST.ql +62 -0
- package/ql/python/tools/src/PrintCFG/PrintCFG.md +52 -0
- package/ql/python/tools/src/PrintCFG/PrintCFG.ql +21 -0
- package/ql/python/tools/src/codeql-pack.lock.yml +30 -0
- package/ql/python/tools/src/codeql-pack.yml +6 -0
- package/ql/ruby/tools/src/CallGraphFrom/CallGraphFrom.ql +40 -0
- package/ql/ruby/tools/src/CallGraphTo/CallGraphTo.ql +48 -0
- package/ql/ruby/tools/src/PrintAST/PrintAST.ql +57 -0
- package/ql/ruby/tools/src/PrintCFG/PrintCFG.md +55 -0
- package/ql/ruby/tools/src/PrintCFG/PrintCFG.ql +22 -0
- package/ql/ruby/tools/src/codeql-pack.lock.yml +24 -0
- package/ql/ruby/tools/src/codeql-pack.yml +6 -0
- package/ql/swift/tools/src/CallGraphFrom/CallGraphFrom.ql +53 -0
- package/ql/swift/tools/src/CallGraphTo/CallGraphTo.ql +49 -0
- package/ql/swift/tools/src/PrintAST/PrintAST.ql +58 -0
- package/ql/swift/tools/src/PrintCFG/PrintCFG.ql +68 -0
- package/ql/swift/tools/src/codeql-pack.lock.yml +24 -0
- package/ql/swift/tools/src/codeql-pack.yml +6 -0
- package/scripts/setup-packs.sh +150 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print CFG for java
|
|
3
|
+
* @description Produces a representation of a file's Control Flow Graph for specified source files.
|
|
4
|
+
* @id java/tools/print-cfg
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags cfg
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import java
|
|
10
|
+
import semmle.code.java.ControlFlowGraph
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Holds if the node is an exit-related CFG node.
|
|
14
|
+
* These nodes are excluded from the output because their ordering
|
|
15
|
+
* is non-deterministic across CodeQL CLI versions.
|
|
16
|
+
*/
|
|
17
|
+
private predicate isExitNode(ControlFlow::Node node) {
|
|
18
|
+
node.toString().matches("%Exit")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for PrintCFG that outputs all CFG nodes and edges,
|
|
23
|
+
* excluding exit nodes for deterministic output.
|
|
24
|
+
*/
|
|
25
|
+
query predicate nodes(ControlFlow::Node node, string property, string value) {
|
|
26
|
+
property = "semmle.label" and
|
|
27
|
+
value = node.toString() and
|
|
28
|
+
not isExitNode(node)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
query predicate edges(ControlFlow::Node pred, ControlFlow::Node succ) {
|
|
32
|
+
pred.getASuccessor() = succ and
|
|
33
|
+
not isExitNode(pred) and
|
|
34
|
+
not isExitNode(succ)
|
|
35
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
lockVersion: 1.0.0
|
|
3
|
+
dependencies:
|
|
4
|
+
codeql/controlflow:
|
|
5
|
+
version: 2.0.25
|
|
6
|
+
codeql/dataflow:
|
|
7
|
+
version: 2.0.25
|
|
8
|
+
codeql/java-all:
|
|
9
|
+
version: 8.0.0
|
|
10
|
+
codeql/mad:
|
|
11
|
+
version: 1.0.41
|
|
12
|
+
codeql/quantum:
|
|
13
|
+
version: 0.0.19
|
|
14
|
+
codeql/rangeanalysis:
|
|
15
|
+
version: 1.0.41
|
|
16
|
+
codeql/regex:
|
|
17
|
+
version: 1.0.41
|
|
18
|
+
codeql/ssa:
|
|
19
|
+
version: 2.0.17
|
|
20
|
+
codeql/threat-models:
|
|
21
|
+
version: 1.0.41
|
|
22
|
+
codeql/tutorial:
|
|
23
|
+
version: 1.0.41
|
|
24
|
+
codeql/typeflow:
|
|
25
|
+
version: 1.0.41
|
|
26
|
+
codeql/typetracking:
|
|
27
|
+
version: 2.0.25
|
|
28
|
+
codeql/util:
|
|
29
|
+
version: 2.0.28
|
|
30
|
+
codeql/xml:
|
|
31
|
+
version: 1.0.41
|
|
32
|
+
compiled: false
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From for javascript
|
|
3
|
+
* @description Displays calls made from a specified function, showing the call graph outbound from the source function.
|
|
4
|
+
* @id javascript/tools/call-graph-from
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import javascript
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the source function name for which to generate the call graph.
|
|
14
|
+
* Can be a single function name or comma-separated list of function names.
|
|
15
|
+
*/
|
|
16
|
+
external string sourceFunction();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets a single source function name from the comma-separated list.
|
|
20
|
+
*/
|
|
21
|
+
string getSourceFunctionName() {
|
|
22
|
+
result = sourceFunction().splitAt(",").trim()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets a function by matching against the selected source function names.
|
|
27
|
+
*/
|
|
28
|
+
Function getSourceFunction() {
|
|
29
|
+
exists(string selectedFunc |
|
|
30
|
+
selectedFunc = getSourceFunctionName() and
|
|
31
|
+
result.getName() = selectedFunc
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
from CallExpr call, Function source
|
|
36
|
+
where
|
|
37
|
+
call.getEnclosingFunction() = source and
|
|
38
|
+
(
|
|
39
|
+
// Use external predicate if available
|
|
40
|
+
source = getSourceFunction()
|
|
41
|
+
or
|
|
42
|
+
// Fallback for unit tests: include test files
|
|
43
|
+
(
|
|
44
|
+
not exists(getSourceFunction()) and
|
|
45
|
+
source.getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
select call,
|
|
49
|
+
"Call from `" + source.getName() + "` to `" + call.getCalleeName() + "`"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph To for javascript
|
|
3
|
+
* @description Displays calls made to a specified function, showing the call graph inbound to the target function.
|
|
4
|
+
* @id javascript/tools/call-graph-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import javascript
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the target function name for which to generate the call graph.
|
|
14
|
+
* Can be a single function name or comma-separated list of function names.
|
|
15
|
+
*/
|
|
16
|
+
external string targetFunction();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets a single target function name from the comma-separated list.
|
|
20
|
+
*/
|
|
21
|
+
string getTargetFunctionName() {
|
|
22
|
+
result = targetFunction().splitAt(",").trim()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets the caller name for a call expression.
|
|
27
|
+
*/
|
|
28
|
+
string getCallerName(CallExpr call) {
|
|
29
|
+
if exists(call.getEnclosingFunction())
|
|
30
|
+
then result = call.getEnclosingFunction().getName()
|
|
31
|
+
else result = "Top-level"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
from CallExpr call
|
|
35
|
+
where
|
|
36
|
+
(
|
|
37
|
+
// Use external predicate if available
|
|
38
|
+
call.getCalleeName() = getTargetFunctionName()
|
|
39
|
+
or
|
|
40
|
+
// Fallback for unit tests: include test files
|
|
41
|
+
(
|
|
42
|
+
not exists(getTargetFunctionName()) and
|
|
43
|
+
call.getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
select call,
|
|
47
|
+
"Call to `" + call.getCalleeName() + "` from `" + getCallerName(call) + "`"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print AST for javascript
|
|
3
|
+
* @description Outputs a representation of the Abstract Syntax Tree for specified source files.
|
|
4
|
+
* @id javascript/tools/print-ast
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags ast
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import javascript
|
|
10
|
+
import semmle.javascript.PrintAst
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the source files to generate AST from.
|
|
14
|
+
* Can be a single file path or comma-separated list of file paths.
|
|
15
|
+
*/
|
|
16
|
+
external string selectedSourceFiles();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets a single source file from the comma-separated list.
|
|
20
|
+
*/
|
|
21
|
+
string getSelectedSourceFile() {
|
|
22
|
+
result = selectedSourceFiles().splitAt(",").trim()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets a file by matching against the selected source file paths.
|
|
27
|
+
*/
|
|
28
|
+
File getSelectedFile() {
|
|
29
|
+
exists(string selectedFile |
|
|
30
|
+
selectedFile = getSelectedSourceFile() and
|
|
31
|
+
(
|
|
32
|
+
// Match by exact relative path from source root
|
|
33
|
+
result.getRelativePath() = selectedFile or
|
|
34
|
+
// Match by file name if no path separators
|
|
35
|
+
(not selectedFile.matches("%/%") and result.getBaseName() = selectedFile) or
|
|
36
|
+
// Match by ending path component
|
|
37
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) = selectedFile
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Configuration for PrintAST that uses external predicates to specify source files.
|
|
44
|
+
* Falls back to test directory structure when external predicates are not available.
|
|
45
|
+
*/
|
|
46
|
+
class Cfg extends PrintAstConfiguration {
|
|
47
|
+
override predicate shouldPrint(Locatable e, Location l) {
|
|
48
|
+
super.shouldPrint(e, l) and
|
|
49
|
+
(
|
|
50
|
+
// Use external predicate if available
|
|
51
|
+
l.getFile() = getSelectedFile()
|
|
52
|
+
or
|
|
53
|
+
// Fallback for unit tests: include test files
|
|
54
|
+
(
|
|
55
|
+
not exists(getSelectedFile()) and
|
|
56
|
+
l.getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Print CFG for JavaScript
|
|
2
|
+
|
|
3
|
+
Produces a representation of a file's Control Flow Graph (CFG) for specified source files.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Control Flow Graph represents the order in which statements and expressions are executed in a program. Each node in the graph represents a control-flow element (statement or expression), and edges represent possible execution paths between them.
|
|
8
|
+
|
|
9
|
+
This query outputs all CFG nodes and their successor relationships for JavaScript code, which is useful for understanding program execution flow, debugging control flow issues, and analyzing code paths.
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Visualizing program execution flow
|
|
16
|
+
- Understanding complex branching logic
|
|
17
|
+
- Debugging control flow issues
|
|
18
|
+
- Analysis of code paths and reachability
|
|
19
|
+
- IDE integration for control flow visualization
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
The following JavaScript code demonstrates control flow through conditional statements and loops:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
function example(x) {
|
|
27
|
+
if (x > 0) {
|
|
28
|
+
// COMPLIANT - Branching creates CFG edges
|
|
29
|
+
console.log('Positive');
|
|
30
|
+
} else {
|
|
31
|
+
console.log('Non-positive');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < 3; i++) {
|
|
35
|
+
// COMPLIANT - Loop creates cyclic CFG
|
|
36
|
+
console.log(i);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
In the resulting CFG:
|
|
42
|
+
|
|
43
|
+
- The `if` condition creates two outgoing edges (true/false branches)
|
|
44
|
+
- The `for` loop creates a cycle back to the condition check
|
|
45
|
+
- Each statement connects to its successor in execution order
|
|
46
|
+
|
|
47
|
+
## Output Format
|
|
48
|
+
|
|
49
|
+
The query produces two relations:
|
|
50
|
+
|
|
51
|
+
- `nodes(ControlFlowNode, string, string)`: Each CFG node with its label
|
|
52
|
+
- `edges(ControlFlowNode, ControlFlowNode)`: Successor relationships between nodes
|
|
53
|
+
|
|
54
|
+
## References
|
|
55
|
+
|
|
56
|
+
- [JavaScript Control Flow](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling)
|
|
57
|
+
- [CodeQL Control Flow Graph](https://codeql.github.com/docs/writing-codeql-queries/about-control-flow-in-codeql/)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print CFG for javascript
|
|
3
|
+
* @description Produces a representation of a file's Control Flow Graph for specified source files.
|
|
4
|
+
* @id javascript/tools/print-cfg
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags cfg
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import javascript
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for PrintCFG that outputs all CFG nodes and edges.
|
|
13
|
+
*/
|
|
14
|
+
query predicate nodes(ControlFlowNode node, string property, string value) {
|
|
15
|
+
property = "semmle.label" and
|
|
16
|
+
value = node.toString()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
query predicate edges(ControlFlowNode pred, ControlFlowNode succ) {
|
|
20
|
+
pred.getASuccessor() = succ
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
lockVersion: 1.0.0
|
|
3
|
+
dependencies:
|
|
4
|
+
codeql/concepts:
|
|
5
|
+
version: 0.0.15
|
|
6
|
+
codeql/controlflow:
|
|
7
|
+
version: 2.0.25
|
|
8
|
+
codeql/dataflow:
|
|
9
|
+
version: 2.0.25
|
|
10
|
+
codeql/javascript-all:
|
|
11
|
+
version: 2.6.21
|
|
12
|
+
codeql/mad:
|
|
13
|
+
version: 1.0.41
|
|
14
|
+
codeql/regex:
|
|
15
|
+
version: 1.0.41
|
|
16
|
+
codeql/ssa:
|
|
17
|
+
version: 2.0.17
|
|
18
|
+
codeql/threat-models:
|
|
19
|
+
version: 1.0.41
|
|
20
|
+
codeql/tutorial:
|
|
21
|
+
version: 1.0.41
|
|
22
|
+
codeql/typetracking:
|
|
23
|
+
version: 2.0.25
|
|
24
|
+
codeql/util:
|
|
25
|
+
version: 2.0.28
|
|
26
|
+
codeql/xml:
|
|
27
|
+
version: 1.0.41
|
|
28
|
+
codeql/yaml:
|
|
29
|
+
version: 1.0.41
|
|
30
|
+
compiled: false
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From for python
|
|
3
|
+
* @description Displays calls made from a specified function, showing the call graph outbound from the source function.
|
|
4
|
+
* @id python/tools/call-graph-from
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import python
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the source function name for which to generate the call graph.
|
|
14
|
+
* Can be a single function name or comma-separated list of function names.
|
|
15
|
+
*/
|
|
16
|
+
external string sourceFunction();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets a single source function name from the comma-separated list.
|
|
20
|
+
*/
|
|
21
|
+
string getSourceFunctionName() {
|
|
22
|
+
result = sourceFunction().splitAt(",").trim()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets a function by matching against the selected source function names.
|
|
27
|
+
*/
|
|
28
|
+
Function getSourceFunction() {
|
|
29
|
+
exists(string selectedFunc |
|
|
30
|
+
selectedFunc = getSourceFunctionName() and
|
|
31
|
+
result.getName() = selectedFunc
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
from CallNode call, Function source
|
|
36
|
+
where
|
|
37
|
+
call.getScope() = source and
|
|
38
|
+
(
|
|
39
|
+
// Use external predicate if available
|
|
40
|
+
source = getSourceFunction()
|
|
41
|
+
or
|
|
42
|
+
// Fallback for unit tests: include test files
|
|
43
|
+
(
|
|
44
|
+
not exists(getSourceFunction()) and
|
|
45
|
+
call.getLocation().getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
select call.getNode(),
|
|
49
|
+
"Call from `" + source.getName() + "` to `" + call.getNode().(Call).getFunc().(Name).getId() + "`"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph To for python
|
|
3
|
+
* @description Displays calls made to a specified function, showing the call graph inbound to the target function.
|
|
4
|
+
* @id python/tools/call-graph-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import python
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the target function name for which to generate the call graph.
|
|
14
|
+
* Can be a single function name or comma-separated list of function names.
|
|
15
|
+
*/
|
|
16
|
+
external string targetFunction();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets a single target function name from the comma-separated list.
|
|
20
|
+
*/
|
|
21
|
+
string getTargetFunctionName() {
|
|
22
|
+
result = targetFunction().splitAt(",").trim()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets the caller name for a call expression.
|
|
27
|
+
*/
|
|
28
|
+
string getCallerName(CallNode call) {
|
|
29
|
+
if exists(call.getScope())
|
|
30
|
+
then result = call.getScope().getName()
|
|
31
|
+
else result = "Module"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
from CallNode call
|
|
35
|
+
where
|
|
36
|
+
(
|
|
37
|
+
// Use external predicate if available
|
|
38
|
+
call.getNode().(Call).getFunc().(Name).getId() = getTargetFunctionName()
|
|
39
|
+
or
|
|
40
|
+
// Fallback for unit tests: include test files
|
|
41
|
+
(
|
|
42
|
+
not exists(getTargetFunctionName()) and
|
|
43
|
+
call.getLocation().getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
select call.getNode(),
|
|
47
|
+
"Call to `" + call.getNode().(Call).getFunc().(Name).getId() + "` from `" + getCallerName(call) + "`"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print AST for python
|
|
3
|
+
* @description Outputs a representation of the Abstract Syntax Tree for specified source files.
|
|
4
|
+
* @id python/tools/print-ast
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags ast
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import semmle.python.PrintAst
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Gets the source files to generate AST from.
|
|
13
|
+
* Can be a single file path or comma-separated list of file paths.
|
|
14
|
+
*/
|
|
15
|
+
external string selectedSourceFiles();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Gets a single source file from the comma-separated list.
|
|
19
|
+
*/
|
|
20
|
+
string getSelectedSourceFile() {
|
|
21
|
+
result = selectedSourceFiles().splitAt(",").trim()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Gets a file by matching against the selected source file paths.
|
|
26
|
+
*/
|
|
27
|
+
File getSelectedFile() {
|
|
28
|
+
exists(string selectedFile |
|
|
29
|
+
selectedFile = getSelectedSourceFile() and
|
|
30
|
+
(
|
|
31
|
+
// Match by exact relative path from source root
|
|
32
|
+
result.getRelativePath() = selectedFile or
|
|
33
|
+
// Match by file name if no path separators
|
|
34
|
+
(not selectedFile.matches("%/%") and result.getBaseName() = selectedFile) or
|
|
35
|
+
// Match by ending path component
|
|
36
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) = selectedFile
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for PrintAST that uses external predicates to specify source files.
|
|
43
|
+
* Falls back to test directory structure when external predicates are not available.
|
|
44
|
+
*/
|
|
45
|
+
class Cfg extends PrintAstConfiguration {
|
|
46
|
+
override predicate shouldPrint(AstNode e, Location l) {
|
|
47
|
+
super.shouldPrint(e, l) and
|
|
48
|
+
(
|
|
49
|
+
// Use external predicate if available
|
|
50
|
+
l.getFile() = getSelectedFile()
|
|
51
|
+
or
|
|
52
|
+
// Fallback for unit tests: include test files
|
|
53
|
+
(
|
|
54
|
+
not exists(getSelectedFile()) and
|
|
55
|
+
l.getFile().getParent().getParent().getBaseName() = "test"
|
|
56
|
+
)
|
|
57
|
+
) and
|
|
58
|
+
// Exclude the "Name" class so that results are deterministic
|
|
59
|
+
// for a given source file, which is required for reproducible results
|
|
60
|
+
not e.getAQlClass() = "Name"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Print CFG for Python
|
|
2
|
+
|
|
3
|
+
Produces a representation of a file's Control Flow Graph (CFG) for specified source files.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Control Flow Graph represents the order in which statements and expressions are executed in a program. Each node in the graph represents a control-flow element (statement or expression), and edges represent possible execution paths between them.
|
|
8
|
+
|
|
9
|
+
This query outputs all CFG nodes and their successor relationships for Python code, which is useful for understanding program execution flow, debugging control flow issues, and analyzing code paths.
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Visualizing program execution flow
|
|
16
|
+
- Understanding complex branching logic
|
|
17
|
+
- Debugging control flow issues
|
|
18
|
+
- Analysis of code paths and reachability
|
|
19
|
+
- IDE integration for control flow visualization
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
The following Python code demonstrates control flow through conditional statements and loops:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
def example(x):
|
|
27
|
+
if x > 0: # COMPLIANT - Branching creates CFG edges
|
|
28
|
+
print("Positive")
|
|
29
|
+
else:
|
|
30
|
+
print("Non-positive")
|
|
31
|
+
|
|
32
|
+
for i in range(3): # COMPLIANT - Loop creates cyclic CFG
|
|
33
|
+
print(i)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
In the resulting CFG:
|
|
37
|
+
|
|
38
|
+
- The `if` condition creates two outgoing edges (true/false branches)
|
|
39
|
+
- The `for` loop creates a cycle back to the iterator
|
|
40
|
+
- Each statement connects to its successor in execution order
|
|
41
|
+
|
|
42
|
+
## Output Format
|
|
43
|
+
|
|
44
|
+
The query produces two relations:
|
|
45
|
+
|
|
46
|
+
- `nodes(ControlFlowNode, string, string)`: Each CFG node with its label
|
|
47
|
+
- `edges(ControlFlowNode, ControlFlowNode)`: Successor relationships between nodes
|
|
48
|
+
|
|
49
|
+
## References
|
|
50
|
+
|
|
51
|
+
- [Python Control Flow](https://docs.python.org/3/tutorial/controlflow.html)
|
|
52
|
+
- [CodeQL Control Flow Graph](https://codeql.github.com/docs/writing-codeql-queries/about-control-flow-in-codeql/)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print CFG for python
|
|
3
|
+
* @description Produces a representation of a file's Control Flow Graph for specified source files.
|
|
4
|
+
* @id python/tools/print-cfg
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags cfg
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import python
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for PrintCFG that outputs all CFG nodes and edges.
|
|
13
|
+
*/
|
|
14
|
+
query predicate nodes(ControlFlowNode node, string property, string value) {
|
|
15
|
+
property = "semmle.label" and
|
|
16
|
+
value = node.toString()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
query predicate edges(ControlFlowNode pred, ControlFlowNode succ) {
|
|
20
|
+
pred.getASuccessor() = succ
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
lockVersion: 1.0.0
|
|
3
|
+
dependencies:
|
|
4
|
+
codeql/concepts:
|
|
5
|
+
version: 0.0.15
|
|
6
|
+
codeql/controlflow:
|
|
7
|
+
version: 2.0.25
|
|
8
|
+
codeql/dataflow:
|
|
9
|
+
version: 2.0.25
|
|
10
|
+
codeql/mad:
|
|
11
|
+
version: 1.0.41
|
|
12
|
+
codeql/python-all:
|
|
13
|
+
version: 6.1.0
|
|
14
|
+
codeql/regex:
|
|
15
|
+
version: 1.0.41
|
|
16
|
+
codeql/ssa:
|
|
17
|
+
version: 2.0.17
|
|
18
|
+
codeql/threat-models:
|
|
19
|
+
version: 1.0.41
|
|
20
|
+
codeql/tutorial:
|
|
21
|
+
version: 1.0.41
|
|
22
|
+
codeql/typetracking:
|
|
23
|
+
version: 2.0.25
|
|
24
|
+
codeql/util:
|
|
25
|
+
version: 2.0.28
|
|
26
|
+
codeql/xml:
|
|
27
|
+
version: 1.0.41
|
|
28
|
+
codeql/yaml:
|
|
29
|
+
version: 1.0.41
|
|
30
|
+
compiled: false
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From for ruby
|
|
3
|
+
* @description Displays calls made from a specified method, showing the call graph outbound from the source method.
|
|
4
|
+
* @id ruby/tools/call-graph-from
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
private import codeql.ruby.AST
|
|
11
|
+
private import codeql.ruby.DataFlow
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets the source method name for which to generate the call graph.
|
|
15
|
+
* Can be a single method name or comma-separated list of method names.
|
|
16
|
+
*/
|
|
17
|
+
external string sourceFunction();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Gets a single source method name from the comma-separated list.
|
|
21
|
+
*/
|
|
22
|
+
string getSourceFunctionName() {
|
|
23
|
+
result = sourceFunction().splitAt(",").trim()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
from MethodCall call, MethodBase source
|
|
27
|
+
where
|
|
28
|
+
call.getEnclosingMethod() = source and
|
|
29
|
+
(
|
|
30
|
+
// Use external predicate if available
|
|
31
|
+
source.getName() = getSourceFunctionName()
|
|
32
|
+
or
|
|
33
|
+
// Fallback for unit tests: include test files
|
|
34
|
+
(
|
|
35
|
+
not exists(getSourceFunctionName()) and
|
|
36
|
+
source.getLocation().getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
select call,
|
|
40
|
+
"Call from `" + source.getName() + "` to `" + call.getMethodName() + "`"
|