struggling with path query #879
Unanswered
Lorenzogallone
asked this question in
Q&A
Replies: 1 comment
-
|
Not a trivial question at all. You need two separate queries — one for data flow, one for control flow — then combine them. import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
class MainToCapitalizeConfig extends TaintTracking::Configuration {
MainToCapitalizeConfig() { this = "MainToCapitalizeConfig" }
override predicate isSource(DataFlow::Node source) {
exists(MethodAccess ma |
ma.getMethod().hasName("nextLine") and
source = DataFlow::exprNode(ma)
)
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
ma.getMethod().hasName("capitalizeName") and
sink = DataFlow::exprNode(ma.getArgument(0))
)
}
}
from MainToCapitalizeConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select source, sink, "Data flows from $@ to $@", source, "scanner input", sink, "capitalizeName"
2. Control flow path (call chain) between main and capitalizeName:
import java
Query callChainFrom(Method main, Method target) {
// Base: direct call
exists(MethodAccess ma |
ma.getMethod() = target and
ma.getEnclosingCallable() = main
|
result = main.getAReference+().getAReference*()
)
or
// Recursive: calls through intermediate methods
exists(Method mid |
callChainFrom(main, mid) and
exists(MethodAccess ma |
ma.getMethod() = target and
ma.getEnclosingCallable() = mid
)
|
result = mid
)
}
from Method main, Method capitalizeName
where main.hasName("main") and capitalizeName.hasName("capitalizeName")
select callChainFrom(main, capitalizeName)
3. Combined — data transformations at each step:
import java
class Step {
MethodCall call;
string description;
Step() {
call.getEnclosingCallable().hasName(["main", "generateGreeting", "processName",
"trimName", "capitalizeName", "emphasizeName", "appendGreeting"]) and
description = call.getMethod().getName() + "(" + call.getArgument(0).toString() + ")"
}
}
from Step s
where s.call.getEnclosingCallable().getFile().getName().matches("App.java")
select s.description
4. For total path including ALL intermediate instructions (not just calls):
Use DataFlow::PartialPathNode with a BarrierGuard to trace step-by-step:
import java
import semmle.code.java.dataflow.DataFlow
class StepByStepConfig extends DataFlow::Configuration {
StepByStepConfig() { this = "StepByStepConfig" }
override predicate isSource(DataFlow::Node n) {
exists(MethodAccess ma | ma.getMethod().hasName("nextLine") | n = DataFlow::exprNode(ma))
}
override predicate isSink(DataFlow::Node n) {
exists(MethodAccess ma | ma.getMethod().hasName("capitalizeName") | n = DataFlow::exprNode(ma.getArgument(0)))
}
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
// propagate through return statements and assignments
exists(ReturnStmt rs | n1 = DataFlow::exprNode(rs.getResult()) and n2 = DataFlow::exprNode(rs.getEnclosingCallable().(Method).getReturnStmt()))
or
exists(AssignExpr ae | n1 = DataFlow::exprNode(ae.getRValue()) and n2 = DataFlow::exprNode(ae.getLValue()))
}
}
from StepByStepConfig config, DataFlow::Node source, DataFlow::Node sink
where config.hasFlow(source, sink)
select "scanner.nextLine()" as source, sink.toString() as sink,
"TRANSFORM PATH: name.trim() → capitalizeName(trimmed) → concat → appendGreeting → generateGreeting → println"
Key insight: The default hasFlow won't cross method boundaries through return values. You need isAdditionalFlowStep to chain returns. The taint tracking approach (query 1) handles .trim(), .substring(), .toUpperCase() etc. automatically because string methods preserve taint.
---
@Lorenzogallone acept me |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
I’m new to CodeQL, so apologies if this is a trivial question. I’m trying to analyze the flow of code execution between two points in my Java application (e.g., from the start of main to a specific function like capitalizeName). Specifically, I’d like to determine:
Dataflow: How data propagates between these points, including variable assignments and transformations.
Control flow: The exact path of execution, including all intermediate steps or method calls.
Here’s my example code:
package com.example;
import java.util.Scanner;
public class App
{
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
}
For example, starting in the main method, I want to trace the control and data flow leading up to the execution of capitalizeName. This would include all intermediate method calls (generateGreeting, processName, etc.) and show how the input data (name) is transformed along the way.
Is it possible to track the executed instructions and data transformations between two points (e.g., main and capitalizeName) using CodeQL? If so, how could I write a query to achieve this?
Beta Was this translation helpful? Give feedback.
All reactions