我想提取一个Java方法的本地数据流,到目前为止,我使用这个查询来提取函数中访问、声明或赋值变量的位置:
/**
* @name Empty block
* @kind problem
* @problem.severity warning
* @id java/example/empty-block
*/
import java
import semmle.code.java.dataflow.DataFlow
from File fl, LocalVariableDeclExpr ld, VarAccess va, Assignment asn
where
fl.getBaseName() = "Calculator.java"
and
ld.getEnclosingCallable().getName()= "calc"
and va.getEnclosingCallable().getName() = "calc"
and asn.getEnclosingCallable().getName() = "calc"
and ld.getLocation().getFile() = fl
and va.getLocation().getFile() = fl
and asn.getLocation().getFile() = fl
and va.getLocation().getStartLine() = ld.getLocation().getStartLine()
select ld, "\"" + va.getVariable().getName()+"\"" + "->" + "\"" +ld.getVariable().getName()+"\"" + "\n" + "\"" +asn.getDest()+"\"" + "->" + "\"" +asn.getSource()+"\"" + "\n"
问题是SELECT阶段花费的时间太长。我使用this存储库作为数据库。文件名为Calculator.Java
,方法如下:
public double calc(double x, String input, char opt) {
inText.setFont(inText.getFont().deriveFont(Font.PLAIN));
double y = Double.parseDouble(input);
switch (opt) {
case '+':
return x + y;
case '-':
return x - y;
case '*':
return x * y;
case '/':
return x / y;
case '%':
return x % y;
case '^':
return Math.pow(x, y);
default:
inText.setFont(inText.getFont().deriveFont(Font.PLAIN));
return y;
}
}
谢谢。
1条答案
按热度按时间qyswt5oh1#
你想要声明、赋值和读取同一个变量吗?因为你的查询目前的编写方式只是选择
calc
方法中任意变量的组合。此外,由于您一直在检查可调用的名称和文件,您的查询可能不是很有性能。为此引入一个单独的变量可能会更有性能(也更容易阅读),请参阅下面的查询代码。
请记住,CodeQL是一种数据库语言,因此在您的示例中,中间结果是元组
(LocalVariableDeclExpr, VarAccess, Assignment)
,这意味着:1.如果变量没有
Assignment
,则查询没有该变量的结果(请注意,局部变量的初始化不被视为Assignment
,请参见GitHub issue)1.你会得到你可能不感兴趣的那个元组的排列,例如:一米四氮一x一米五氮一x一米六氮一x
因此,对于每个变量获取
VarAccess
(它涵盖了对变量的阅读访问)可能会更有趣,例如:还要注意,您的查询与 dataflow 无关,它只查找变量的声明、赋值和使用。它们不一定是正确的(甚至任何)顺序。有关跟踪数据流的更多信息,请参见documentation。也许您还对使用路径查询可视化数据流感兴趣。考虑数据流和污点跟踪之间的差异也很重要。数据流只涵盖变量和调用之间流动的值完全相同的情况,而污点跟踪还涵盖值被转换或变换的情况,例如从字符串获得子字符串(另请参见文档)。