Codeql提取Java方法的本地数据流花费的时间太长

5anewei6  于 2023-03-06  发布在  Java
关注(0)|答案(1)|浏览(117)

我想提取一个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;
        }
    }

谢谢。

qyswt5oh

qyswt5oh1#

你想要声明、赋值和读取同一个变量吗?因为你的查询目前的编写方式只是选择calc方法中任意变量的组合。
此外,由于您一直在检查可调用的名称和文件,您的查询可能不是很有性能。为此引入一个单独的变量可能会更有性能(也更容易阅读),请参阅下面的查询代码。
请记住,CodeQL是一种数据库语言,因此在您的示例中,中间结果是元组(LocalVariableDeclExpr, VarAccess, Assignment),这意味着:
1.如果变量没有Assignment,则查询没有该变量的结果(请注意,局部变量的初始化不被视为Assignment,请参见GitHub issue
1.你会得到你可能不感兴趣的那个元组的排列,例如:一米四氮一x一米五氮一x一米六氮一x
因此,对于每个变量获取VarAccess(它涵盖了对变量的阅读访问)可能会更有趣,例如:

import java

from Method method, LocalVariableDeclExpr ld, VarAccess va
where
  method.getDeclaringType().hasName("Calculator") and
  method.hasName("calc") and
  ld.getEnclosingCallable() = method and
  va.getEnclosingCallable() = method and
  // And both belong to the same variable
  ld.getVariable() = va.getVariable()
select ld, va

还要注意,您的查询与 dataflow 无关,它只查找变量的声明、赋值和使用。它们不一定是正确的(甚至任何)顺序。有关跟踪数据流的更多信息,请参见documentation。也许您还对使用路径查询可视化数据流感兴趣。考虑数据流和污点跟踪之间的差异也很重要。数据流只涵盖变量和调用之间流动的值完全相同的情况,而污点跟踪还涵盖值被转换或变换的情况,例如从字符串获得子字符串(另请参见文档)。

相关问题