From 5b992f3e724ff00c642b9ee9fc47a24bccf79ba0 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Thu, 5 Dec 2024 15:52:34 +0300 Subject: [PATCH 1/4] Remove jacodb-analysis module Also remove jacodb-examples, jacodb-panda-static and some tests in jacodb-ets, since they heavily depend on jacodb-analysis --- build.gradle.kts | 2 - jacodb-analysis/README.md | 75 - jacodb-analysis/build.gradle.kts | 32 - .../org/jacodb/analysis/config/Condition.kt | 158 - .../org/jacodb/analysis/config/Position.kt | 102 - .../org/jacodb/analysis/config/TaintAction.kt | 70 - .../analysis/graph/ApplicationGraphFactory.kt | 63 - .../jacodb/analysis/graph/BackwardGraphs.kt | 71 - .../analysis/graph/JcApplicationGraphImpl.kt | 72 - .../org/jacodb/analysis/graph/JcNoopInst.kt | 33 - .../graph/SimplifiedJcApplicationGraph.kt | 149 - .../org/jacodb/analysis/ifds/AccessPath.kt | 69 - .../org/jacodb/analysis/ifds/Accessors.kt | 34 - .../org/jacodb/analysis/ifds/Analyzer.kt | 36 - .../kotlin/org/jacodb/analysis/ifds/Edge.kt | 36 - .../org/jacodb/analysis/ifds/FlowFunctions.kt | 110 - .../org/jacodb/analysis/ifds/IfdsResult.kt | 135 - .../org/jacodb/analysis/ifds/Manager.kt | 43 - .../kotlin/org/jacodb/analysis/ifds/Reason.kt | 43 - .../kotlin/org/jacodb/analysis/ifds/Runner.kt | 283 - .../org/jacodb/analysis/ifds/Summary.kt | 109 - .../org/jacodb/analysis/ifds/TraceGraph.kt | 66 - .../org/jacodb/analysis/ifds/UnitResolver.kt | 103 - .../kotlin/org/jacodb/analysis/ifds/Vertex.kt | 32 - .../impl/custom/AbstractFlowAnalysis.kt | 38 - .../impl/custom/BackwardFlowAnalysis.kt | 28 - .../analysis/impl/custom/FlowAnalysis.kt | 39 - .../analysis/impl/custom/FlowAnalysisImpl.kt | 409 -- .../impl/custom/ForwardFlowAnalysis.kt | 28 - .../impl/custom/NullAssumptionAnalysis.kt | 229 - .../custom/ReachingDefinitionsAnalysis.kt | 102 - .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 124 - .../jacodb/analysis/npe/NpeFlowFunctions.kt | 665 --- .../org/jacodb/analysis/npe/NpeManager.kt | 67 - .../kotlin/org/jacodb/analysis/npe/Utils.kt | 59 - .../kotlin/org/jacodb/analysis/sarif/Sarif.kt | 153 - .../analysis/sarif/SourceFileResolver.kt | 23 - .../jacodb/analysis/sarif/Vulnerability.kt | 32 - .../kotlin/org/jacodb/analysis/taint/Sarif.kt | 33 - .../analysis/taint/TaintAnalysisOptions.kt | 23 - .../jacodb/analysis/taint/TaintAnalyzers.kt | 221 - .../jacodb/analysis/taint/TaintBidiRunner.kt | 154 - .../org/jacodb/analysis/taint/TaintEvents.kt | 40 - .../org/jacodb/analysis/taint/TaintFacts.kt | 31 - .../analysis/taint/TaintFlowFunctions.kt | 827 --- .../org/jacodb/analysis/taint/TaintManager.kt | 336 -- .../jacodb/analysis/taint/TaintSummaries.kt | 32 - .../kotlin/org/jacodb/analysis/taint/Types.kt | 25 - .../org/jacodb/analysis/unused/Sarif.kt | 29 - .../analysis/unused/UnusedVariableAnalyzer.kt | 56 - .../analysis/unused/UnusedVariableEvents.kt | 31 - .../analysis/unused/UnusedVariableFacts.kt | 31 - .../unused/UnusedVariableFlowFunctions.kt | 120 - .../analysis/unused/UnusedVariableManager.kt | 267 - .../unused/UnusedVariableSummaries.kt | 32 - .../org/jacodb/analysis/unused/Utils.kt | 67 - .../org/jacodb/analysis/util/EtsTraits.kt | 165 - .../org/jacodb/analysis/util/JcTraits.kt | 229 - .../jacodb/analysis/util/PandaStaticTraits.kt | 232 - .../kotlin/org/jacodb/analysis/util/Traits.kt | 61 - .../kotlin/org/jacodb/analysis/util/Utils.kt | 48 - .../analysis/impl/JavaAnalysisApiTest.java | 80 - .../jacodb/analysis/impl/BaseAnalysisTest.kt | 137 - .../analysis/impl/ConditionEvaluatorTest.kt | 339 -- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 249 - .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 119 - .../org/jacodb/analysis/impl/IfdsTaintTest.kt | 54 - .../impl/IfdsUntrustedLoopBoundTest.kt | 73 - .../jacodb/analysis/impl/IfdsUnusedTest.kt | 93 - .../analysis/impl/JodaDateTimeAnalysisTest.kt | 83 - .../impl/NullabilityAssumptionAnalysisTest.kt | 70 - .../analysis/impl/TaintFlowFunctionsTest.kt | 224 - .../src/test/resources/additional.json | 607 --- .../src/test/resources/config_small.json | 789 --- .../src/test/resources/config_test.json | 174 - .../config_untrusted_loop_bound.json | 45 - .../src/test/resources/pointerbench.jar | Bin 32004 -> 0 bytes .../test/resources/simplelogger.properties | 34 - jacodb-cli/build.gradle.kts | 15 - .../src/main/kotlin/org/jacodb/cli/main.kt | 185 - .../src/test/kotlin/org/jacodb/cli/CliTest.kt | 31 - jacodb-cli/src/test/resources/config.json | 9 - jacodb-ets/build.gradle.kts | 2 - .../org/jacodb/ets/utils/LoadEtsFile.kt | 24 + .../kotlin/org/jacodb/ets/test/EtsIfds.kt | 433 -- .../org/jacodb/ets/test/EtsProjectAnalysis.kt | 153 - .../org/jacodb/ets/test/EtsSceneTest.kt | 183 - .../jacodb/ets/test/EtsTaintAnalysisTest.kt | 141 - .../org/jacodb/ets/test/utils/Entrypoints.kt | 2 - .../org/jacodb/ets/test/utils/TaintConfig.kt | 110 - jacodb-examples/build.gradle.kts | 19 - .../jacodb/examples/JavaReadMeExamples.java | 145 - .../jacodb/examples/KotlinReadMeExamples.kt | 125 - .../examples/analysis/PerformanceMetrics.kt | 198 - .../analysis/SootPerformanceMetrics.kt | 130 - jacodb-panda-static/build.gradle.kts | 26 - .../org/jacodb/panda/staticvm/cfg/Graph.kt | 151 - .../org/jacodb/panda/staticvm/cfg/GraphExt.kt | 124 - .../panda/staticvm/cfg/InstListBuilder.kt | 857 --- .../panda/staticvm/cfg/OutputVarBuilder.kt | 392 -- .../jacodb/panda/staticvm/cfg/PandaExpr.kt | 503 -- .../panda/staticvm/cfg/PandaGraphToDot.kt | 40 - .../jacodb/panda/staticvm/cfg/PandaInst.kt | 183 - .../panda/staticvm/cfg/PandaInstList.kt | 73 - .../panda/staticvm/classpath/AccessFlags.kt | 38 - .../panda/staticvm/classpath/ClassNodes.kt | 137 - .../panda/staticvm/classpath/Intrinsics.kt | 49 - .../staticvm/classpath/PandaPrimitives.kt | 50 - .../panda/staticvm/classpath/PandaProject.kt | 210 - .../jacodb/panda/staticvm/classpath/Types.kt | 102 - .../jacodb/panda/staticvm/ets/Parameter.kt | 31 - .../org/jacodb/panda/staticvm/ets/Type.kt | 872 --- .../org/jacodb/panda/staticvm/ir/EtsStdlib.kt | 31 - .../jacodb/panda/staticvm/ir/PandaInstIr.kt | 1269 ----- .../panda/staticvm/ir/PandaInstIrVisitor.kt | 97 - .../panda/staticvm/ir/PandaProgramIr.kt | 215 - .../panda/staticvm/ir/PandaProgramIrToDot.kt | 161 - .../jacodb/panda/staticvm/utils/GraphUtils.kt | 117 - .../org/jacodb/panda/staticvm/utils/Loops.kt | 117 - .../panda/staticvm/utils/OneDirectionGraph.kt | 46 - .../org/jacodb/panda/staticvm/utils/Utils.kt | 29 - .../src/main/resources/intrinsics.json | 1892 ------- .../src/test/kotlin/panda/PandaDemoCases.kt | 146 - .../src/test/kotlin/panda/PandaIfdsTest.kt | 134 - .../panda/PandaIrDeserializationTest.kt | 84 - .../src/test/kotlin/panda/TestUtils.kt | 87 - .../src/test/resources/Program2.ets | 32 - .../src/test/resources/Program2.ir | 1163 ---- .../src/test/resources/cases/case1.ets | 13 - .../src/test/resources/cases/case1.ir | 966 ---- .../src/test/resources/cases/case2.ets | 34 - .../src/test/resources/cases/case2.ir | 1860 ------- .../src/test/resources/cases/case3.ets | 38 - .../src/test/resources/cases/case3.ir | 3122 ----------- .../src/test/resources/cases/case4.ets | 99 - .../src/test/resources/cases/case4.ir | 4544 ---------------- .../src/test/resources/sample.abc.ir | 4788 ----------------- .../src/test/resources/sample.ets | 94 - .../test/resources/simplelogger.properties | 39 - .../src/test/resources/testCatch.ets | 43 - .../src/test/resources/testCatch.ir | 1911 ------- settings.gradle.kts | 4 - 142 files changed, 24 insertions(+), 39076 deletions(-) delete mode 100644 jacodb-analysis/README.md delete mode 100644 jacodb-analysis/build.gradle.kts delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt delete mode 100644 jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt delete mode 100644 jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt delete mode 100644 jacodb-analysis/src/test/resources/additional.json delete mode 100644 jacodb-analysis/src/test/resources/config_small.json delete mode 100644 jacodb-analysis/src/test/resources/config_test.json delete mode 100644 jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json delete mode 100644 jacodb-analysis/src/test/resources/pointerbench.jar delete mode 100644 jacodb-analysis/src/test/resources/simplelogger.properties delete mode 100644 jacodb-cli/build.gradle.kts delete mode 100644 jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt delete mode 100644 jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt delete mode 100644 jacodb-cli/src/test/resources/config.json delete mode 100644 jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt delete mode 100644 jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt delete mode 100644 jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt delete mode 100644 jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt delete mode 100644 jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt delete mode 100644 jacodb-examples/build.gradle.kts delete mode 100644 jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java delete mode 100644 jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt delete mode 100644 jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt delete mode 100644 jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt delete mode 100644 jacodb-panda-static/build.gradle.kts delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt delete mode 100644 jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt delete mode 100644 jacodb-panda-static/src/main/resources/intrinsics.json delete mode 100644 jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt delete mode 100644 jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt delete mode 100644 jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt delete mode 100644 jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt delete mode 100644 jacodb-panda-static/src/test/resources/Program2.ets delete mode 100644 jacodb-panda-static/src/test/resources/Program2.ir delete mode 100644 jacodb-panda-static/src/test/resources/cases/case1.ets delete mode 100644 jacodb-panda-static/src/test/resources/cases/case1.ir delete mode 100644 jacodb-panda-static/src/test/resources/cases/case2.ets delete mode 100644 jacodb-panda-static/src/test/resources/cases/case2.ir delete mode 100644 jacodb-panda-static/src/test/resources/cases/case3.ets delete mode 100644 jacodb-panda-static/src/test/resources/cases/case3.ir delete mode 100644 jacodb-panda-static/src/test/resources/cases/case4.ets delete mode 100644 jacodb-panda-static/src/test/resources/cases/case4.ir delete mode 100644 jacodb-panda-static/src/test/resources/sample.abc.ir delete mode 100644 jacodb-panda-static/src/test/resources/sample.ets delete mode 100644 jacodb-panda-static/src/test/resources/simplelogger.properties delete mode 100644 jacodb-panda-static/src/test/resources/testCatch.ets delete mode 100644 jacodb-panda-static/src/test/resources/testCatch.ir diff --git a/build.gradle.kts b/build.gradle.kts index 15947c5cf..cc93e1660 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -172,11 +172,9 @@ if (!repoUrl.isNullOrEmpty()) { project(":jacodb-api-storage"), project(":jacodb-core"), project(":jacodb-storage"), - project(":jacodb-analysis"), project(":jacodb-approximations"), project(":jacodb-taint-configuration"), project(":jacodb-ets"), - project(":jacodb-panda-static"), ) ) { tasks { diff --git a/jacodb-analysis/README.md b/jacodb-analysis/README.md deleted file mode 100644 index cb6a4b854..000000000 --- a/jacodb-analysis/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Module `jacodb-analysis` - -The `jacodb-analysis` module allows launching application dataflow analyses. -It contains an API to write custom analyses, and several ready-to-use analyses. - -## Units - -The [IFDS](https://dx.doi.org/10.1145/199448.199462) framework is the basis for this module. -To make the implementation scalable, the analyzed code is split into the so-called units, so that the framework -can analyze them concurrently. -Information is shared between the units via summaries, but the lifecycle of each unit is controlled -separately. - -## Get started - -The analysis entry point is the [runAnalysis] method. To call it, you have to provide: -* `graph` — an application graph that is used for analysis. To obtain this graph, one should call the [newApplicationGraphForAnalysis] method. -* `unitResolver` — an object that groups methods into units. Choose one from `UnitResolversLibrary`. -Note that, in general, larger units mean more precise but also more resource-consuming analysis. -* `ifdsUnitRunnerFactory` — an [IfdsUnitRunnerFactory] instance, that can create runners. Runners are used to analyze each unit. -So this factory is what define concrete analysis. - Ready-to-use runner factories are located in `RunnersLibrary`. -* `methods` — a list of methods to analyze. - -For example, to detect the unused variables in the given `analyzedClass` methods, you may run the following code -(assuming that `classpath` is an instance of [JcClasspath]): - -```kotlin -val applicationGraph = runBlocking { - classpath.newApplicationGraphForAnalysis() -} - -val methodsToAnalyze = analyzedClass.declaredMethods -val unitResolver = MethodUnitResolver -val runnerFactory = UnusedVariableRunnerFactory - -runAnalysis(applicationGraph, unitResolver, runnerFactory, methodsToAnalyze) -``` - -## Implemented runners - -By now, the following runners are implemented: -* `UnusedVariableRunner` that can detect issues like unused variable declaration, unused `return` value, etc. -* `NpeRunner` that can find instructions with possible `null` value dereference. -* Generic `TaintRunner` that can perform taint analysis. -* `SqlInjectionRunner`, which finds places vulnerable to SQL injections, thus performing a specific kind of taint - analysis. - -## Implementing your own analysis - -To implement a simple one-pass analysis, use [IfdsBaseUnitRunnerFactory]. -To instantiate it, you need an [AnalyzerFactory] instance, which is an object that can create [Analyzer] via -[JcApplicationGraph]. - -To instantiate an [Analyzer] interface, you have to specify the following: - -* `flowFunctions`, which describe the dataflow facts and their transmissions during the analysis; - -* semantics for these dataflow facts, i.e. how these facts produce vulnerabilities, summaries, etc. -This should be done by implementing `handleNewEdge`, `handleNewCrossUnitCall` and `handleIfdsResult` methods. - -To implement bidirectional analysis, you may use composite [BidiIfdsUnitRunnerFactory]. - - - - -[runAnalysis]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis/run-analysis.html -[newApplicationGraphForAnalysis]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.graph/new-application-graph-for-analysis.html -[IfdsUnitRunnerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-ifds-unit-runner-factory/index.html -[JcClasspath]: https://jacodb.org/docs/jacodb-api/org.jacodb.api/-jc-classpath/index.html -[IfdsBaseUnitRunnerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-ifds-base-unit-runner-factory/index.html -[AnalyzerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-analyzer-factory/index.html -[Analyzer]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-analyzer/index.html -[JcApplicationGraph]: https://jacodb.org/docs/jacodb-api/org.jacodb.api.analysis/-jc-application-graph/index.html -[BidiIfdsUnitRunnerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-bidi-ifds-unit-runner-factory/index.html \ No newline at end of file diff --git a/jacodb-analysis/build.gradle.kts b/jacodb-analysis/build.gradle.kts deleted file mode 100644 index dd121df72..000000000 --- a/jacodb-analysis/build.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -plugins { - kotlin("plugin.serialization") - `java-test-fixtures` -} - -dependencies { - api(project(":jacodb-api-jvm")) - api(project(":jacodb-core")) - api(project(":jacodb-taint-configuration")) - api(project(":jacodb-ets")) - api(project(":jacodb-panda-static")) - - implementation(Libs.kotlin_logging) - implementation(Libs.slf4j_simple) - implementation(Libs.kotlinx_coroutines_core) - implementation(Libs.kotlinx_serialization_json) - api(Libs.sarif4k) - - testImplementation(project(":jacodb-api-jvm")) - testImplementation(testFixtures(project(":jacodb-core"))) - testImplementation(testFixtures(project(":jacodb-storage"))) - testImplementation(kotlin("test")) - testImplementation(Libs.mockk) - - // Additional deps for analysis: - testImplementation(files("src/test/resources/pointerbench.jar")) - testImplementation(Libs.joda_time) - testImplementation(Libs.juliet_support) - for (cweNum in listOf(89, 476, 563, 690)) { - testImplementation(Libs.juliet_cwe(cweNum)) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt deleted file mode 100644 index af05a9dd1..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.config - -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.removeTrailingElementAccessors -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.api.jvm.ext.isAssignable -import org.jacodb.taint.configuration.And -import org.jacodb.taint.configuration.AnnotationType -import org.jacodb.taint.configuration.ConditionVisitor -import org.jacodb.taint.configuration.ConstantEq -import org.jacodb.taint.configuration.ConstantGt -import org.jacodb.taint.configuration.ConstantLt -import org.jacodb.taint.configuration.ConstantMatches -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.IsConstant -import org.jacodb.taint.configuration.IsType -import org.jacodb.taint.configuration.Not -import org.jacodb.taint.configuration.Or -import org.jacodb.taint.configuration.PositionResolver -import org.jacodb.taint.configuration.SourceFunctionMatches -import org.jacodb.taint.configuration.TypeMatches - -// TODO: replace 'JcInt' with 'CommonInt', etc - -context(Traits) -open class BasicConditionEvaluator( - internal val positionResolver: PositionResolver>, -) : ConditionVisitor { - - override fun visit(condition: ConstantTrue): Boolean { - return true - } - - override fun visit(condition: Not): Boolean { - return !condition.arg.accept(this) - } - - override fun visit(condition: And): Boolean { - return condition.args.all { it.accept(this) } - } - - override fun visit(condition: Or): Boolean { - return condition.args.any { it.accept(this) } - } - - override fun visit(condition: IsType): Boolean { - // Note: TaintConfigurationFeature.ConditionSpecializer is responsible for - // expanding IsType condition upon parsing the taint configuration. - error("Unexpected condition: $condition") - } - - override fun visit(condition: AnnotationType): Boolean { - // Note: TaintConfigurationFeature.ConditionSpecializer is responsible for - // expanding AnnotationType condition upon parsing the taint configuration. - error("Unexpected condition: $condition") - } - - override fun visit(condition: IsConstant): Boolean { - positionResolver.resolve(condition.position).onSome { - return it.isConstant() - } - return false - } - - override fun visit(condition: ConstantEq): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.eqConstant(condition.value) - } - return false - } - - override fun visit(condition: ConstantLt): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.ltConstant(condition.value) - } - return false - } - - override fun visit(condition: ConstantGt): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.gtConstant(condition.value) - } - return false - } - - override fun visit(condition: ConstantMatches): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.matches(condition.pattern) - } - return false - } - - override fun visit(condition: SourceFunctionMatches): Boolean { - TODO("Not implemented yet") - } - - override fun visit(condition: ContainsMark): Boolean { - error("This visitor does not support condition $condition. Use FactAwareConditionEvaluator instead") - } - - override fun visit(condition: TypeMatches): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return when (value) { - is JcValue -> { - value.type.isAssignable(condition.type) - } - - else -> error("Cannot evaluate $condition for $value") - } - } - return false - } -} - -context(Traits) -class FactAwareConditionEvaluator( - private val fact: Tainted, - positionResolver: PositionResolver>, -) : BasicConditionEvaluator(positionResolver) { - - override fun visit(condition: ContainsMark): Boolean { - if (fact.mark != condition.mark) return false - positionResolver.resolve(condition.position).onSome { value -> - val variable = value.toPath() - - // FIXME: Adhoc for arrays - val variableWithoutStars = variable.removeTrailingElementAccessors() - val factWithoutStars = fact.variable.removeTrailingElementAccessors() - if (variableWithoutStars == factWithoutStars) return true - - return variable == fact.variable - } - return false - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt deleted file mode 100644 index e0842c397..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.config - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.fmap -import org.jacodb.analysis.ifds.toMaybe -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonProject -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonInstanceCallExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.taint.configuration.AnyArgument -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.Position -import org.jacodb.taint.configuration.PositionResolver -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.ResultAnyElement -import org.jacodb.taint.configuration.This - -context(Traits) -class CallPositionToAccessPathResolver( - private val callStatement: CommonInst, -) : PositionResolver> { - private val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - override fun resolve(position: Position): Maybe = when (position) { - AnyArgument -> Maybe.none() - is Argument -> callExpr.args[position.index].toPathOrNull().toMaybe() - This -> (callExpr as? CommonInstanceCallExpr)?.instance?.toPathOrNull().toMaybe() - Result -> (callStatement as? CommonAssignInst)?.lhv?.toPathOrNull().toMaybe() - ResultAnyElement -> (callStatement as? CommonAssignInst)?.lhv?.toPathOrNull().toMaybe() - .fmap { it + ElementAccessor } - } -} - -context(Traits) -class CallPositionToValueResolver( - private val callStatement: CommonInst, -) : PositionResolver> { - private val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - override fun resolve(position: Position): Maybe = when (position) { - AnyArgument -> Maybe.none() - is Argument -> Maybe.some(callExpr.args[position.index]) - This -> (callExpr as? CommonInstanceCallExpr)?.instance.toMaybe() - Result -> (callStatement as? CommonAssignInst)?.lhv.toMaybe() - ResultAnyElement -> Maybe.none() - } -} - -context(Traits) -class EntryPointPositionToValueResolver( - private val method: CommonMethod, -) : PositionResolver> { - override fun resolve(position: Position): Maybe = when (position) { - This -> Maybe.some(method.thisInstance) - - is Argument -> { - val p = method.parameters[position.index] - getArgument(p).toMaybe() - } - - AnyArgument, Result, ResultAnyElement -> error("Unexpected $position") - } -} - -context(Traits) -class EntryPointPositionToAccessPathResolver( - private val method: CommonMethod, -) : PositionResolver> { - override fun resolve(position: Position): Maybe = when (position) { - This -> method.thisInstance.toPathOrNull().toMaybe() - - is Argument -> { - val p = method.parameters[position.index] - getArgument(p)?.toPathOrNull().toMaybe() - } - - AnyArgument, Result, ResultAnyElement -> error("Unexpected $position") - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt deleted file mode 100644 index 59403b099..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.config - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.fmap -import org.jacodb.analysis.ifds.map -import org.jacodb.analysis.taint.Tainted -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.CopyMark -import org.jacodb.taint.configuration.PositionResolver -import org.jacodb.taint.configuration.RemoveAllMarks -import org.jacodb.taint.configuration.RemoveMark - -class TaintActionEvaluator( - private val positionResolver: PositionResolver>, -) { - fun evaluate(action: CopyAllMarks, fact: Tainted): Maybe> = - positionResolver.resolve(action.from).map { from -> - if (from != fact.variable) return@map Maybe.none() - positionResolver.resolve(action.to).fmap { to -> - setOf(fact, fact.copy(variable = to)) - } - } - - fun evaluate(action: CopyMark, fact: Tainted): Maybe> { - if (fact.mark != action.mark) return Maybe.none() - return positionResolver.resolve(action.from).map { from -> - if (from != fact.variable) return@map Maybe.none() - positionResolver.resolve(action.to).fmap { to -> - setOf(fact, fact.copy(variable = to)) - } - } - } - - fun evaluate(action: AssignMark): Maybe> = - positionResolver.resolve(action.position).fmap { variable -> - setOf(Tainted(variable, action.mark)) - } - - fun evaluate(action: RemoveAllMarks, fact: Tainted): Maybe> = - positionResolver.resolve(action.position).map { variable -> - if (variable != fact.variable) return@map Maybe.none() - Maybe.some(emptySet()) - } - - fun evaluate(action: RemoveMark, fact: Tainted): Maybe> { - if (fact.mark != action.mark) return Maybe.none() - return positionResolver.resolve(action.position).map { variable -> - if (variable != fact.variable) return@map Maybe.none() - Maybe.some(emptySet()) - } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt deleted file mode 100644 index 026256ffb..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:JvmName("ApplicationGraphFactory") - -package org.jacodb.analysis.graph - -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.future.future -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.impl.features.usagesExt -import java.util.concurrent.CompletableFuture - -/** - * Creates an instance of [SimplifiedJcApplicationGraph], see its docs for more info. - */ -suspend fun JcClasspath.newApplicationGraphForAnalysis( - bannedPackagePrefixes: List? = null, -): JcApplicationGraph { - val mainGraph = JcApplicationGraphImpl(this, usagesExt()) - return if (bannedPackagePrefixes != null) { - SimplifiedJcApplicationGraph(mainGraph, bannedPackagePrefixes) - } else { - SimplifiedJcApplicationGraph(mainGraph, defaultBannedPackagePrefixes) - } -} - -/** - * Async adapter for calling [newApplicationGraphForAnalysis] from Java. - * - * See also: [answer on StackOverflow](https://stackoverflow.com/a/52887677/3592218). - */ -@OptIn(DelicateCoroutinesApi::class) -fun JcClasspath.newApplicationGraphForAnalysisAsync( - bannedPackagePrefixes: List? = null, -): CompletableFuture = - GlobalScope.future { - newApplicationGraphForAnalysis(bannedPackagePrefixes) - } - -val defaultBannedPackagePrefixes: List = listOf( - "kotlin.", - "java.", - "jdk.internal.", - "sun.", - "com.sun.", - "javax.", -) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt deleted file mode 100644 index f3bf2e601..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:JvmName("BackwardApplicationGraphs") - -package org.jacodb.analysis.graph - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst - -private class BackwardApplicationGraphImpl( - val forward: ApplicationGraph, -) : ApplicationGraph - where Method : CommonMethod, - Statement : CommonInst { - - override fun predecessors(node: Statement) = forward.successors(node) - override fun successors(node: Statement) = forward.predecessors(node) - - override fun callees(node: Statement) = forward.callees(node) - override fun callers(method: Method) = forward.callers(method) - - override fun entryPoints(method: Method) = forward.exitPoints(method) - override fun exitPoints(method: Method) = forward.entryPoints(method) - - override fun methodOf(node: Statement) = forward.methodOf(node) -} - -@Suppress("UNCHECKED_CAST") -val ApplicationGraph.reversed: ApplicationGraph - where Method : CommonMethod, - Statement : CommonInst - get() = when (this) { - is JcApplicationGraph -> this.reversed as ApplicationGraph - is BackwardApplicationGraphImpl -> this.forward - else -> BackwardApplicationGraphImpl(this) - } - -private class BackwardJcApplicationGraphImpl( - val forward: JcApplicationGraph, -) : JcApplicationGraph, - ApplicationGraph by BackwardApplicationGraphImpl(forward) { - - override val cp: JcClasspath - get() = forward.cp -} - -val JcApplicationGraph.reversed: JcApplicationGraph - get() = if (this is BackwardJcApplicationGraphImpl) { - this.forward - } else { - BackwardJcApplicationGraphImpl(this) - } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt deleted file mode 100644 index c0001b11a..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.graph - -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.impl.features.SyncUsagesExtension - -/** - * Possible we will need JcRawInst instead of JcInst - */ -open class JcApplicationGraphImpl( - override val cp: JcClasspath, - private val usages: SyncUsagesExtension, -) : JcApplicationGraph { - override fun predecessors(node: JcInst): Sequence { - val graph = node.location.method.flowGraph() - val predecessors = graph.predecessors(node) - val throwers = graph.throwers(node) - return predecessors.asSequence() + throwers.asSequence() - } - - override fun successors(node: JcInst): Sequence { - val graph = node.location.method.flowGraph() - val successors = graph.successors(node) - val catchers = graph.catchers(node) - return successors.asSequence() + catchers.asSequence() - } - - override fun callees(node: JcInst): Sequence { - val callExpr = node.callExpr ?: return emptySequence() - return sequenceOf(callExpr.method.method) - } - - override fun callers(method: JcMethod): Sequence { - return usages.findUsages(method).flatMap { - it.flowGraph().instructions.asSequence().filter { inst -> - val callExpr = inst.callExpr ?: return@filter false - callExpr.method.method == method - } - } - } - - override fun entryPoints(method: JcMethod): Sequence { - return method.flowGraph().entries.asSequence() - } - - override fun exitPoints(method: JcMethod): Sequence { - return method.flowGraph().exits.asSequence() - } - - override fun methodOf(node: JcInst): JcMethod { - return node.location.method - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt deleted file mode 100644 index c57d9123d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.graph - -import org.jacodb.api.jvm.cfg.JcExpr -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstLocation -import org.jacodb.api.jvm.cfg.JcInstVisitor - -data class JcNoopInst(override val location: JcInstLocation) : JcInst { - override val operands: List - get() = emptyList() - - override fun accept(visitor: JcInstVisitor): T { - return visitor.visitExternalJcInst(this) - } - - override fun toString(): String = "noop" -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt deleted file mode 100644 index 83388c0f9..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.graph - -import kotlinx.coroutines.runBlocking -import org.jacodb.api.jvm.JcClassType -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcVirtualCallExpr -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.isSubClassOf -import org.jacodb.impl.cfg.JcInstLocationImpl -import org.jacodb.impl.features.hierarchyExt - -/** - * This is adopted specially for IFDS [JcApplicationGraph] that - * 1. Ignores method calls matching [bannedPackagePrefixes] (i.e., treats them as simple instructions with no callees) - * 2. In [callers] returns only call sites that were visited before - * 3. Adds a special [JcNoopInst] instruction to the beginning of each method - * (because backward analysis may want for method to start with neutral instruction) - */ -internal class SimplifiedJcApplicationGraph( - private val graph: JcApplicationGraph, - private val bannedPackagePrefixes: List, -) : JcApplicationGraph by graph { - private val hierarchyExtension = runBlocking { - cp.hierarchyExt() - } - - private val visitedCallers: MutableMap> = mutableMapOf() - - private val cache: MutableMap> = mutableMapOf() - - // For backward analysis we may want for method to start with "neutral" operation => - // we add noop to the beginning of every method - private fun getStartInst(method: JcMethod): JcNoopInst { - val lineNumber = method.flowGraph().entries.firstOrNull()?.lineNumber?.let { it - 1 } ?: -1 - return JcNoopInst(JcInstLocationImpl(method, -1, lineNumber)) - } - - override fun predecessors(node: JcInst): Sequence { - val method = methodOf(node) - return when (node) { - getStartInst(method) -> { - emptySequence() - } - - in graph.entryPoints(method) -> { - sequenceOf(getStartInst(method)) - } - - else -> { - graph.predecessors(node) - } - } - } - - override fun successors(node: JcInst): Sequence { - val method = methodOf(node) - return when (node) { - getStartInst(method) -> { - graph.entryPoints(method) - } - - else -> { - graph.successors(node) - } - } - } - - private fun getOverrides(method: JcMethod): List { - return if (cache.containsKey(method)) { - cache[method]!! - } else { - val res = hierarchyExtension.findOverrides(method).toList() - cache[method] = res - res - } - } - - private fun calleesUnmarked(node: JcInst): Sequence { - val callees = graph.callees(node).filterNot { callee -> - bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) } - } - - val callExpr = node.callExpr as? JcVirtualCallExpr ?: return callees - val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass ?: return callees - - return callees - .flatMap { callee -> - val allOverrides = getOverrides(callee) - .filter { - it.enclosingClass isSubClassOf instanceClass || - // TODO: use only down-most override here - instanceClass isSubClassOf it.enclosingClass - } - - // TODO: maybe filter inaccessible methods here? - allOverrides + sequenceOf(callee) - } - } - - override fun callees(node: JcInst): Sequence { - return calleesUnmarked(node).also { - it.forEach { method -> - visitedCallers.getOrPut(method) { mutableSetOf() }.add(node) - } - } - } - - /** - * This is IFDS-algorithm aware optimization. - * In IFDS we don't need all method callers, we need only method callers which we visited earlier. - */ - // TODO: Think if this optimization is really needed - override fun callers(method: JcMethod): Sequence = - visitedCallers[method].orEmpty().asSequence() - - override fun entryPoints(method: JcMethod): Sequence = try { - sequenceOf(getStartInst(method)) - } catch (e: Throwable) { - // we couldn't find instructions list - // TODO: maybe fix flowGraph() - emptySequence() - } - - override fun exitPoints(method: JcMethod): Sequence = try { - graph.exitPoints(method) - } catch (e: Throwable) { - // we couldn't find instructions list - // TODO: maybe fix flowGraph() - emptySequence() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt deleted file mode 100644 index ad7ba3123..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonValue - -data class AccessPath internal constructor( - val value: CommonValue?, - val accesses: List, -) { - init { - if (value == null) { - require(accesses.isNotEmpty()) - val a = accesses[0] - require(a is FieldAccessor) - require(a.isStatic) - } - } - - fun limit(n: Int): AccessPath = AccessPath(value, accesses.take(n)) - - operator fun plus(accesses: List): AccessPath { - for (accessor in accesses) { - if (accessor is FieldAccessor && accessor.isStatic) { - throw IllegalArgumentException("Unexpected static field: ${accessor.name}") - } - } - - return AccessPath(value, this.accesses + accesses) - } - - operator fun plus(accessor: Accessor): AccessPath { - if (accessor is FieldAccessor && accessor.isStatic) { - throw IllegalArgumentException("Unexpected static field: ${accessor.name}") - } - - return AccessPath(value, this.accesses + accessor) - } - - override fun toString(): String { - return value.toString() + accesses.joinToString("") { it.toSuffix() } - } -} - -val AccessPath.isOnHeap: Boolean - get() = accesses.isNotEmpty() - -val AccessPath.isStatic: Boolean - get() = value == null - -operator fun AccessPath.minus(other: AccessPath): List? { - if (value != other.value) return null - if (accesses.take(other.accesses.size) != other.accesses) return null - return accesses.drop(other.accesses.size) -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt deleted file mode 100644 index 22a29c38e..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -sealed interface Accessor { - fun toSuffix(): String -} - -data class FieldAccessor( - val name: String, - val isStatic: Boolean = false, -) : Accessor { - override fun toSuffix(): String = ".${name}" - override fun toString(): String = name -} - -object ElementAccessor : Accessor { - override fun toSuffix(): String = "[*]" - override fun toString(): String = "*" -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt deleted file mode 100644 index 00e24c1ca..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -interface Analyzer - where Method : CommonMethod, - Statement : CommonInst { - - val flowFunctions: FlowFunctions - - fun handleNewEdge( - edge: Edge, - ): List - - fun handleCrossUnitCall( - caller: Vertex, - callee: Vertex, - ): List -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt deleted file mode 100644 index 9ed0e27cc..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -data class Edge( - val from: Vertex, - val to: Vertex, -) { - init { - require(from.method == to.method) - } - - val method: CommonMethod - get() = from.method - - override fun toString(): String { - return "(${from.fact} at ${from.statement}) -> (${to.fact} at ${to.statement}) in $method" - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt deleted file mode 100644 index c6878bc39..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -fun interface FlowFunction { - fun compute(fact: Fact): Collection -} - -interface FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - /** - * Method for obtaining initial domain facts at the method entrypoint. - * Commonly, it is only `listOf(Zero)`. - */ - fun obtainPossibleStartFacts(method: Method): Collection - - /** - * Sequent flow function. - * - * ``` - * [ DO() ] :: current - * | - * | (sequent edge) - * | - * [ DO() ] - * ``` - */ - fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ): FlowFunction - - /** - * Call-to-return-site flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : - * : (call-to-return-site edge) - * : - * [ RETURN FROM p ] :: returnSite - * ``` - */ - fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - ): FlowFunction - - /** - * Call-to-start flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : \ - * : \ (call-to-start edge) - * : \ - * : [ START p ] - * : | - * : [ EXIT p ] - * : / - * : / - * [ RETURN FROM p ] - * ``` - */ - fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ): FlowFunction - - /** - * Exit-to-return-site flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : \ - * : \ - * : [ START p ] - * : | - * : [ EXIT p ] :: exitStatement - * : / - * : / (exit-to-return-site edge) - * : / - * [ RETURN FROM p ] :: returnSite - * ``` - */ - fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - exitStatement: Statement, - ): FlowFunction -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt deleted file mode 100644 index 51e2e6fa1..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonInst - -/** - * Aggregates all facts and edges found by the tabulation algorithm. - */ -class IfdsResult internal constructor( - val pathEdgesBySink: Map, Collection>>, - val facts: Map>, - val reasons: Map, Set>>, - val zeroFact: Fact, -) { - - constructor( - pathEdges: Collection>, - facts: Map>, - reasons: Map, Set>>, - zeroFact: Fact, - ) : this( - pathEdges.groupByTo(HashMap()) { it.to }, - facts, - reasons, - zeroFact - ) - - fun buildTraceGraph(sink: Vertex): TraceGraph { - val sources: MutableSet> = - hashSetOf() - val edges: MutableMap, MutableSet>> = - hashMapOf() - val unresolvedCrossUnitCalls: MutableMap, MutableSet>> = - hashMapOf() - val visited: MutableSet, Vertex>> = - hashSetOf() - - fun addEdge( - from: Vertex, - to: Vertex, - ) { - if (from != to) { - edges.getOrPut(from) { hashSetOf() }.add(to) - } - } - - fun dfs( - edge: Edge, - lastVertex: Vertex, - stopAtMethodStart: Boolean, - ) { - if (!visited.add(edge to lastVertex)) { - return - } - - // Note: loop-edge represents method start - if (stopAtMethodStart && edge.from == edge.to) { - addEdge(edge.from, lastVertex) - return - } - - val vertex = edge.to - if (vertex.fact == zeroFact) { - addEdge(vertex, lastVertex) - sources.add(vertex) - return - } - - for (reason in reasons[edge].orEmpty()) { - when (reason) { - is Reason.Sequent -> { - val predEdge = reason.edge - if (predEdge.to.fact == vertex.fact) { - dfs(predEdge, lastVertex, stopAtMethodStart) - } else { - addEdge(predEdge.to, lastVertex) - dfs(predEdge, predEdge.to, stopAtMethodStart) - } - } - - is Reason.CallToStart -> { - val predEdge = reason.edge - if (!stopAtMethodStart) { - addEdge(predEdge.to, lastVertex) - dfs(predEdge, predEdge.to, false) - } - } - - is Reason.ThroughSummary -> { - val predEdge = reason.edge - val summaryEdge = reason.summaryEdge - addEdge(summaryEdge.to, lastVertex) // Return to next vertex - addEdge(predEdge.to, summaryEdge.from) // Call to start - dfs(summaryEdge, summaryEdge.to, true) // Expand summary edge - dfs(predEdge, predEdge.to, stopAtMethodStart) // Continue normal analysis - } - - is Reason.CrossUnitCall -> { - addEdge(edge.to, lastVertex) - unresolvedCrossUnitCalls.getOrPut(reason.caller) { hashSetOf() }.add(edge.to) - } - - is Reason.External -> { - TODO("External reason is not supported yet") - } - - is Reason.Initial -> { - sources.add(vertex) - addEdge(edge.to, lastVertex) - } - } - } - } - - for (edge in pathEdgesBySink[sink].orEmpty()) { - dfs(edge, edge.to, false) - } - return TraceGraph(sink, sources, edges, unresolvedCrossUnitCalls) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt deleted file mode 100644 index 85541f581..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import kotlinx.coroutines.CoroutineScope -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -interface Manager - where Method : CommonMethod, - Statement : CommonInst { - - fun handleEvent(event: Event) - - fun handleControlEvent(event: ControlEvent) - - fun subscribeOnSummaryEdges( - method: @UnsafeVariance Method, - scope: CoroutineScope, - handler: (Edge) -> Unit, - ) -} - -sealed interface ControlEvent - -data class QueueEmptinessChanged( - val runner: Runner<*, *, *>, - val isEmpty: Boolean, -) : ControlEvent diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt deleted file mode 100644 index a0a3396bf..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonInst - -sealed interface Reason { - - object Initial : Reason - - object External : Reason - - data class CrossUnitCall( - val caller: Vertex, - ) : Reason - - data class Sequent( - val edge: Edge, - ) : Reason - - data class CallToStart( - val edge: Edge, - ) : Reason - - data class ThroughSummary( - val edge: Edge, - val summaryEdge: Edge, - ) : Reason -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt deleted file mode 100644 index 06b7f2ea2..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.getOrElse -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.isActive -import org.jacodb.analysis.graph.JcNoopInst -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.ets.base.EtsStmt -import java.util.concurrent.ConcurrentHashMap -import org.jacodb.api.jvm.ext.cfg.callExpr as jcCallExpr -import org.jacodb.ets.utils.callExpr as etsCallExpr -import org.jacodb.panda.staticvm.cfg.PandaInst as StaticPandaInst -import org.jacodb.panda.staticvm.utils.callExpr as staticPandaCallExpr - -private val logger = mu.KotlinLogging.logger {} - -interface Runner - where Method : CommonMethod, - Statement : CommonInst { - - val graph: ApplicationGraph - val unit: UnitType - - suspend fun run(startMethods: List) - fun submitNewEdge(edge: Edge, reason: Reason) - fun getIfdsResult(): IfdsResult -} - -class UniRunner( - private val manager: Manager, - override val graph: ApplicationGraph, - private val analyzer: Analyzer, - private val unitResolver: UnitResolver, - override val unit: UnitType, - private val zeroFact: Fact, -) : Runner - where Method : CommonMethod, - Statement : CommonInst { - - private val Statement.callExpr: CommonCallExpr? - get() = when (this) { - is JcInst -> jcCallExpr - is StaticPandaInst -> staticPandaCallExpr - is EtsStmt -> etsCallExpr - else -> error("Unsupported statement type: $this") - } - - private val flowSpace: FlowFunctions = analyzer.flowFunctions - private val workList: Channel> = Channel(Channel.UNLIMITED) - internal val pathEdges: MutableSet> = ConcurrentHashMap.newKeySet() - private val reasons = - ConcurrentHashMap, MutableSet>>() - - private val summaryEdges: MutableMap, MutableSet>> = - hashMapOf() - private val callerPathEdgeOf: MutableMap, MutableSet>> = - hashMapOf() - - private val queueIsEmpty = QueueEmptinessChanged(runner = this, isEmpty = true) - private val queueIsNotEmpty = QueueEmptinessChanged(runner = this, isEmpty = false) - - override suspend fun run(startMethods: List) { - for (method in startMethods) { - addStart(method) - } - - tabulationAlgorithm() - } - - private fun addStart(method: Method) { - require(unitResolver.resolve(method) == unit) - val startFacts = flowSpace.obtainPossibleStartFacts(method) - for (startFact in startFacts) { - for (start in graph.entryPoints(method)) { - val vertex = Vertex(start, startFact) - val edge = Edge(vertex, vertex) // loop - propagate(edge, Reason.Initial) - } - } - } - - override fun submitNewEdge(edge: Edge, reason: Reason) { - propagate(edge, reason) - } - - private fun propagate( - edge: Edge, - reason: Reason, - ): Boolean { - val method = graph.methodOf(edge.from.statement) - require(unitResolver.resolve(method) == unit) { - "Propagated edge must be in the same unit" - } - - reasons.computeIfAbsent(edge) { ConcurrentHashMap.newKeySet() }.add(reason) - - // Handle only NEW edges: - if (pathEdges.add(edge)) { - val doPrintOnlyForward = true - val doPrintZero = false - if (!doPrintOnlyForward || edge.from.statement is JcNoopInst) { - if (doPrintZero || edge.to.fact != TaintZeroFact) { - logger.trace { - "Propagating edge=${edge} in method=${method.name} with reason=${reason}" - } - } - } - - // Send edge to analyzer/manager: - for (event in analyzer.handleNewEdge(edge)) { - manager.handleEvent(event) - } - - // Add edge to worklist: - workList.trySend(edge).getOrThrow() - - return true - } - - return false - } - - private suspend fun tabulationAlgorithm() = coroutineScope { - while (isActive) { - val edge = workList.tryReceive().getOrElse { - manager.handleControlEvent(queueIsEmpty) - val edge = workList.receive() - manager.handleControlEvent(queueIsNotEmpty) - edge - } - tabulationAlgorithmStep(edge, this@coroutineScope) - } - } - - private val Method.isExtern: Boolean - get() = unitResolver.resolve(this) != unit - - private fun tabulationAlgorithmStep( - currentEdge: Edge, - scope: CoroutineScope, - ) { - val (startVertex, currentVertex) = currentEdge - val (current, currentFact) = currentVertex - - val currentCallees = graph.callees(current).toList() - val currentIsCall = current.callExpr != null - val currentIsExit = current in graph.exitPoints(graph.methodOf(current)) - - if (currentIsCall) { - // Propagate through the call-to-return-site edge: - for (returnSite in graph.successors(current)) { - val factsAtReturnSite = flowSpace - .obtainCallToReturnSiteFlowFunction(current, returnSite) - .compute(currentFact) - for (returnSiteFact in factsAtReturnSite) { - val returnSiteVertex = Vertex(returnSite, returnSiteFact) - val newEdge = Edge(startVertex, returnSiteVertex) - propagate(newEdge, Reason.Sequent(currentEdge)) - } - } - - // Propagate through the call: - for (callee in currentCallees) { - for (calleeStart in graph.entryPoints(callee)) { - val factsAtCalleeStart = flowSpace - .obtainCallToStartFlowFunction(current, calleeStart) - .compute(currentFact) - for (calleeStartFact in factsAtCalleeStart) { - val calleeStartVertex = Vertex(calleeStart, calleeStartFact) - - if (callee.isExtern) { - // Initialize analysis of callee: - for (event in analyzer.handleCrossUnitCall(currentVertex, calleeStartVertex)) { - manager.handleEvent(event) - } - - // Subscribe on summary edges: - manager.subscribeOnSummaryEdges(callee, scope) { summaryEdge -> - if (summaryEdge.from == calleeStartVertex) { - handleSummaryEdge(currentEdge, summaryEdge) - } else { - logger.trace { "Skipping unsuitable summary edge: $summaryEdge" } - } - } - } else { - // Save info about the call for summary edges that will be found later: - callerPathEdgeOf.getOrPut(calleeStartVertex) { hashSetOf() }.add(currentEdge) - - // Initialize analysis of callee: - run { - val newEdge = Edge(calleeStartVertex, calleeStartVertex) // loop - propagate(newEdge, Reason.CallToStart(currentEdge)) - } - - // Handle already-found summary edges: - for (exitVertex in summaryEdges[calleeStartVertex].orEmpty()) { - val summaryEdge = Edge(calleeStartVertex, exitVertex) - handleSummaryEdge(currentEdge, summaryEdge) - } - } - } - } - } - } else { - if (currentIsExit) { - // Propagate through the summary edge: - for (callerPathEdge in callerPathEdgeOf[startVertex].orEmpty()) { - handleSummaryEdge(currentEdge = callerPathEdge, summaryEdge = currentEdge) - } - - // Add new summary edge: - summaryEdges.getOrPut(startVertex) { hashSetOf() }.add(currentVertex) - } - - // Simple (sequential) propagation to the next instruction: - for (next in graph.successors(current)) { - val factsAtNext = flowSpace - .obtainSequentFlowFunction(current, next) - .compute(currentFact) - for (nextFact in factsAtNext) { - val nextVertex = Vertex(next, nextFact) - val newEdge = Edge(startVertex, nextVertex) - propagate(newEdge, Reason.Sequent(currentEdge)) - } - } - } - } - - private fun handleSummaryEdge( - currentEdge: Edge, - summaryEdge: Edge, - ) { - val (startVertex, currentVertex) = currentEdge - val caller = currentVertex.statement - for (returnSite in graph.successors(caller)) { - val (exit, exitFact) = summaryEdge.to - val finalFacts = flowSpace - .obtainExitToReturnSiteFlowFunction(caller, returnSite, exit) - .compute(exitFact) - for (returnSiteFact in finalFacts) { - val returnSiteVertex = Vertex(returnSite, returnSiteFact) - val newEdge = Edge(startVertex, returnSiteVertex) - propagate(newEdge, Reason.ThroughSummary(currentEdge, summaryEdge)) - } - } - } - - private fun getFinalFacts(): Map> { - val resultFacts: MutableMap> = hashMapOf() - for (edge in pathEdges) { - resultFacts.getOrPut(edge.to.statement) { hashSetOf() }.add(edge.to.fact) - } - return resultFacts - } - - override fun getIfdsResult(): IfdsResult { - val facts = getFinalFacts() - return IfdsResult(pathEdges, facts, reasons, zeroFact) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt deleted file mode 100644 index c7e06ef31..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst -import java.util.concurrent.ConcurrentHashMap - -/** - * A common interface for anything that should be remembered - * and used after the analysis of some unit is completed. - */ -interface Summary { - val method: Method -} - -interface SummaryEdge : Summary { - - val edge: Edge - - override val method: CommonMethod - get() = edge.method -} - -interface Vulnerability : Summary { - val message: String - val sink: Vertex - - override val method: CommonMethod - get() = sink.method -} - -/** - * Contains summaries for many methods and allows to update them and subscribe for them. - */ -interface SummaryStorage> { - - /** - * A list of all methods for which summaries are not empty. - */ - val knownMethods: List - - /** - * Adds [summary] the summaries storage of its method. - */ - fun add(summary: T) - - /** - * @return a flow with all facts summarized for the given [method]. - * Already received facts, along with the facts that will be sent to this storage later, - * will be emitted to the returned flow. - */ - fun getFacts(method: CommonMethod): Flow - - /** - * @return a list will all facts summarized for the given [method] so far. - */ - fun getCurrentFacts(method: CommonMethod): List -} - -class SummaryStorageImpl> : SummaryStorage { - - private val summaries = ConcurrentHashMap>() - private val outFlows = ConcurrentHashMap>() - - override val knownMethods: List - get() = summaries.keys.toList() - - private fun getFlow(method: CommonMethod): MutableSharedFlow { - return outFlows.computeIfAbsent(method) { - MutableSharedFlow(replay = Int.MAX_VALUE) - } - } - - override fun add(summary: T) { - val isNew = summaries.computeIfAbsent(summary.method) { - ConcurrentHashMap.newKeySet() - }.add(summary) - if (isNew) { - val flow = getFlow(summary.method) - check(flow.tryEmit(summary)) - } - } - - override fun getFacts(method: CommonMethod): SharedFlow { - return getFlow(method) - } - - override fun getCurrentFacts(method: CommonMethod): List { - return getFacts(method).replayCache - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt deleted file mode 100644 index 13de77959..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonInst - -data class TraceGraph( - val sink: Vertex, - val sources: MutableSet>, - val edges: MutableMap, MutableSet>>, - val unresolvedCrossUnitCalls: Map, Set>>, -) { - - /** - * Returns all traces from [sources] to [sink]. - */ - fun getAllTraces(): Sequence>> = - sources.asSequence().flatMap { getAllTraces(mutableListOf(it)) } - - private fun getAllTraces( - trace: MutableList>, - ): Sequence>> = sequence { - val v = trace.last() - if (v == sink) { - yield(trace.toList()) // copy list - return@sequence - } - for (u in edges[v].orEmpty()) { - if (u !in trace) { - trace.add(u) - yieldAll(getAllTraces(trace)) - trace.removeLast() - } - } - } - - /** - * Merges [upGraph] into this graph. - */ - fun mergeWithUpGraph( - upGraph: TraceGraph, - entryPoints: Set>, - ) { - sources.addAll(upGraph.sources) - - for (edge in upGraph.edges) { - edges.getOrPut(edge.key) { hashSetOf() }.addAll(edge.value) - } - - edges.getOrPut(upGraph.sink) { hashSetOf() }.addAll(entryPoints) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt deleted file mode 100644 index 5afa581af..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("FunctionName") - -package org.jacodb.analysis.ifds - -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.ext.packageName - -interface UnitType - -data class MethodUnit(val method: JcMethod) : UnitType { - override fun toString(): String { - return "MethodUnit(${method.name})" - } -} - -data class ClassUnit(val clazz: JcClassOrInterface) : UnitType { - override fun toString(): String { - return "ClassUnit(${clazz.simpleName})" - } -} - -data class PackageUnit(val packageName: String) : UnitType { - override fun toString(): String { - return "PackageUnit($packageName)" - } -} - -object SingletonUnit : UnitType { - override fun toString(): String = javaClass.simpleName -} - -object UnknownUnit : UnitType { - override fun toString(): String = javaClass.simpleName -} - -/** - * Sets a mapping from a [Method] to abstract domain [UnitType]. - * - * Therefore, it splits all methods into units, containing one or more method each - * (unit is a set of methods with same value of [UnitType] returned by [resolve]). - * - * To get more info about how it is used in analysis, see [runAnalysis]. - */ -fun interface UnitResolver { - fun resolve(method: Method): UnitType - - companion object { - fun getByName(name: String): UnitResolver = when (name) { - "method" -> MethodUnitResolver - "class" -> ClassUnitResolver(false) - "package" -> PackageUnitResolver - "singleton" -> SingletonUnitResolver - else -> error("Unknown unit resolver '$name'") - } - } -} - -fun interface JcUnitResolver : UnitResolver - -val MethodUnitResolver = JcUnitResolver { method -> - MethodUnit(method) -} - -private val ClassUnitResolverWithNested = JcUnitResolver { method -> - val clazz = generateSequence(method.enclosingClass) { it.outerClass }.last() - ClassUnit(clazz) -} -private val ClassUnitResolverWithoutNested = JcUnitResolver { method -> - val clazz = method.enclosingClass - ClassUnit(clazz) -} - -fun ClassUnitResolver(includeNested: Boolean) = - if (includeNested) { - ClassUnitResolverWithNested - } else { - ClassUnitResolverWithoutNested - } - -val PackageUnitResolver = JcUnitResolver { method -> - PackageUnit(method.enclosingClass.packageName) -} - -val SingletonUnitResolver = JcUnitResolver { - SingletonUnit -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt deleted file mode 100644 index a3830ee6b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -data class Vertex( - val statement: Statement, - val fact: Fact, -) { - val method: CommonMethod - get() = statement.method - - override fun toString(): String { - return "$fact at $statement in $method" - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt deleted file mode 100644 index 492c41c86..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -abstract class AbstractFlowAnalysis(override val graph: JcBytecodeGraph) : FlowAnalysis { - - override fun newEntryFlow(): T = newFlow() - - protected open fun merge(successor: NODE, income1: T, income2: T, outcome: T) { - merge(income1, income2, outcome) - } - - open fun ins(s: NODE): T? { - return ins[s] - } - - protected fun mergeInto(successor: NODE, input: T, incoming: T) { - val tmp = newFlow() - merge(successor, input, incoming, tmp) - copy(tmp, input) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt deleted file mode 100644 index 53c35774b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -abstract class BackwardFlowAnalysis(graph: JcBytecodeGraph) : FlowAnalysisImpl(graph) { - - override val isForward: Boolean = false - - override fun run() { - runAnalysis(FlowAnalysisDirection.BACKWARD, outs, ins) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt deleted file mode 100644 index 105ed664d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -interface FlowAnalysis { - - val ins: MutableMap - val outs: MutableMap - - val graph: JcBytecodeGraph - - val isForward: Boolean - - fun newFlow(): T - - fun newEntryFlow(): T - - fun merge(in1: T, in2: T, out: T) - - fun copy(source: T?, dest: T) - - fun run() -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt deleted file mode 100644 index 454436c19..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph -import org.jacodb.api.jvm.cfg.JcGotoInst -import java.util.* - -enum class Flow { - IN { - override fun getFlow(e: FlowEntry): F? { - return e.inFlow - } - }, - OUT { - override fun getFlow(e: FlowEntry): F? { - return e.outFlow - } - }; - - abstract fun getFlow(e: FlowEntry): F? -} - -/** - * Creates a new `Entry` graph based on a `JcGraph`. This includes pseudo topological order, local - * access for predecessors and successors, a graph entry-point, connected component marker. - */ -private fun JcBytecodeGraph.newScope( - direction: FlowAnalysisDirection, - entryFlow: T, - isForward: Boolean, -): List> { - val size = toList().size - val s = ArrayDeque>(size) - val scope = ArrayList>(size) - val visited = HashMap>((size + 1) * 4 / 3) - - // out of scope node - val instructions: List? - val actualEntries = direction.entries(this) - if (actualEntries.isNotEmpty()) { - // normal cases: there is at least - // one return statement for a backward analysis - // or one entry statement for a forward analysis - instructions = actualEntries - } else { - // cases without any entry statement - if (isForward) { - // case of a forward flow analysis on - // a method without any entry point - throw RuntimeException("No entry point for method in forward analysis") - } else { - // case of backward analysis on - // a method which potentially has - // an infinite loop and no return statement - instructions = ArrayList() - val head = entries.first() - - // collect all 'goto' statements to catch the 'goto' from the infinite loop - val visitedInst = HashSet() - val list = arrayListOf(head) - var temp: NODE - while (list.isNotEmpty()) { - temp = list.removeAt(0) - visitedInst.add(temp) - - // only add 'goto' statements - if (temp is JcGotoInst) { - instructions.add(temp) - } - for (next in successors(temp)) { - if (visitedInst.contains(next)) { - continue - } - list.add(next) - } - } - - if (instructions.isEmpty()) { - throw RuntimeException("Backward analysis on an empty entry set.") - } - } - } - val root = RootEntry() - root.visitEntry(instructions, visited) - root.inFlow = entryFlow - root.outFlow = entryFlow - - val sv: Array?> = arrayOfNulls(size) - val si = IntArray(size) - var index = 0 - var i = 0 - var entry: FlowEntry = root - while (true) { - if (i < entry.outs.size) { - val next = entry.outs[i++] - - // an unvisited child node - if (next.number == Int.MIN_VALUE) { - next.number = s.size - s.add(next) - next.visitEntry(direction.outOf(this, next.data), visited) - - // save old - si[index] = i - sv[index] = entry - index++ - i = 0 - entry = next - } - } else { - if (index == 0) { - assert(scope.size <= size) - scope.reverse() - return scope - } - scope.add(entry) - s.pop(entry) - - // restore old - index-- - entry = sv[index]!! - i = si[index] - } - } -} - -private fun FlowEntry.visitEntry( - instructions: List, - visited: MutableMap>, -): Array> { - val n = instructions.size - return Array(n) { - instructions[it].toEntry(this, visited) - }.also { - outs = it - } -} - -private fun NODE.toEntry( - pred: FlowEntry, - visited: MutableMap>, -): FlowEntry { - // either we reach a new node or a merge node, the latter one is rare - // so put and restore should be better that a lookup - - val newEntry = LeafEntry(this, pred) - val oldEntry = visited.putIfAbsent(this, newEntry) ?: return newEntry - - // no restore required - - // adding self ref (real strongly connected with itself) - if (oldEntry === pred) { - oldEntry.isStronglyConnected = true - } - - // merge nodes are rare, so this is ok - val length = oldEntry.ins.size - oldEntry.ins = Arrays.copyOf(oldEntry.ins, length + 1) - oldEntry.ins[length] = pred - return oldEntry -} - -private fun Deque>.pop(entry: FlowEntry) { - var min = entry.number - for (e in entry.outs) { - assert(e.number > Int.MIN_VALUE) - min = min.coerceAtMost(e.number) - } - - // not our SCC - if (min != entry.number) { - entry.number = min - return - } - - // we only want real SCCs (size > 1) - var last = removeLast() - last.number = Int.MAX_VALUE - if (last === entry) { - return - } - last.isStronglyConnected = true - while (true) { - last = removeLast() - assert(last.number >= entry.number) - last.isStronglyConnected = true - last.number = Int.MAX_VALUE - if (last === entry) { - assert(last.ins.size >= 2) - return - } - } -} - -enum class FlowAnalysisDirection { - BACKWARD { - override fun entries(g: JcBytecodeGraph): List { - return g.exits - } - - override fun outOf(g: JcBytecodeGraph, s: NODE): List { - return g.predecessors(s).toList() - } - }, - FORWARD { - override fun entries(g: JcBytecodeGraph): List { - return g.entries - } - - override fun outOf(g: JcBytecodeGraph, s: NODE): List { - return g.successors(s).toList() - } - }; - - abstract fun entries(g: JcBytecodeGraph): List - abstract fun outOf(g: JcBytecodeGraph, s: NODE): List -} - -abstract class FlowEntry(pred: FlowEntry?) { - - abstract val data: NODE - - var number = Int.MIN_VALUE - var isStronglyConnected = false - var ins: Array> = pred?.let { arrayOf(pred) } ?: emptyArray() - var outs: Array> = emptyArray() - var inFlow: T? = null - var outFlow: T? = null - - override fun toString(): String { - return data.toString() - } - -} - -class RootEntry : FlowEntry(null) { - override val data: NODE get() = throw IllegalStateException() -} - -class LeafEntry(override val data: NODE, pred: FlowEntry?) : FlowEntry(pred) - -abstract class FlowAnalysisImpl(graph: JcBytecodeGraph) : AbstractFlowAnalysis(graph) { - - protected abstract fun flowThrough(instIn: T?, ins: NODE, instOut: T) - - fun outs(s: NODE): T { - return outs[s] ?: newFlow() - } - - override fun ins(s: NODE): T { - return ins[s] ?: newFlow() - } - - private fun Iterable>.initFlow() { - // If a node has only a single in-flow, the in-flow is always equal - // to the out-flow if its predecessor, so we use the same object. - // this saves memory and requires less object creation and copy calls. - - // Furthermore a node can be marked as `canSkip`, this allows us to use - // the same "flow-set" for out-flow and in-flow. T merge node with within - // a real scc cannot be omitted, as it could cause endless loops within - // the fixpoint-iteration! - for (node in this) { - var omit = true - val inFlow: T - val outFlow: T - - if (node.ins.size > 1) { - inFlow = newFlow() - - // no merge points in loops - omit = !node.isStronglyConnected - } else { - assert(node.ins.size == 1) { "Missing head" } - val flow = getFlow(node.ins.first(), node) - assert(flow != null) { "Topological order is broken" } - inFlow = flow!! - } - if (omit && node.data.canSkip) { - // We could recalculate the graph itself but that is more expensive than - // just falling through such nodes. - outFlow = inFlow - } else { - outFlow = newFlow() - } - node.inFlow = inFlow - node.outFlow = outFlow - - ins[node.data] = inFlow - outs[node.data] = outFlow - } - } - - /** - * If a flow node can be skipped return `true`, otherwise `false`. There is no guarantee a node will - * be omitted. `canSkip` node does not influence the result of an analysis. - * - * If you are unsure, don't overwrite this method - */ - protected open val NODE.canSkip: Boolean - get() { - return false - } - - protected open fun getFlow(from: NODE, mergeNode: NODE) = Flow.OUT - - private fun getFlow(o: FlowEntry, e: FlowEntry): T? { - return if (o.inFlow === o.outFlow) { - o.outFlow - } else { - getFlow(o.data, e.data).getFlow(o) - } - } - - private fun FlowEntry.meetFlows() { - assert(ins.isNotEmpty()) - if (ins.size > 1) { - var copy = true - for (o in ins) { - val flow = getFlow(o, this) - val inFlow = inFlow - if (flow != null && inFlow != null) { - if (copy) { - copy = false - copy(flow, inFlow) - } else { - mergeInto(data, inFlow, flow) - } - } - } - } - } - - open fun runAnalysis( - direction: FlowAnalysisDirection, - inFlow: Map, - outFlow: Map, - ): Int { - val scope = graph.newScope(direction, newEntryFlow(), isForward).also { - it.initFlow() - } - val queue = PriorityQueue> { o1, o2 -> o1.number.compareTo(o2.number) } - .also { it.addAll(scope) } - - // Perform fixed point flow analysis - var numComputations = 0 - while (true) { - val entry = queue.poll() ?: return numComputations - entry.meetFlows() - - val hasChanged = flowThrough(entry) - - // Update queue appropriately - if (hasChanged) { - queue.addAll(entry.outs.toList()) - } - numComputations++ - } - } - - private fun flowThrough(entry: FlowEntry): Boolean { - if (entry.inFlow === entry.outFlow) { - assert(!entry.isStronglyConnected || entry.ins.size == 1) - return true - } - if (entry.isStronglyConnected) { - // A flow node that is influenced by at least one back-reference. - // It's essential to check if "flowThrough" changes the result. - // This requires the calculation of "equals", which itself - // can be really expensive - depending on the used flow-model. - // Depending on the "merge"+"flowThrough" costs, it can be cheaper - // to fall through. Only nodes with real back-references always - // need to be checked for changes - val out = newFlow() - flowThrough(entry.inFlow, entry.data, out) - if (out == entry.outFlow) { - return false - } - // copy back the result, as it has changed - entry.outFlow?.let { - copy(out, it) - } - return true - } - - // no back-references, just calculate "flowThrough" - val outFlow = entry.outFlow - if (outFlow != null) { - flowThrough(entry.inFlow, entry.data, outFlow) - } - return true - } - -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt deleted file mode 100644 index 935283ca3..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -abstract class ForwardFlowAnalysis(graph: JcBytecodeGraph) : FlowAnalysisImpl(graph) { - - override val isForward = true - - override fun run() { - runAnalysis(FlowAnalysisDirection.FORWARD, ins, outs) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt deleted file mode 100644 index 091762420..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.JcRefType -import org.jacodb.api.jvm.cfg.JcArrayAccess -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcCastExpr -import org.jacodb.api.jvm.cfg.JcEnterMonitorInst -import org.jacodb.api.jvm.cfg.JcFieldRef -import org.jacodb.api.jvm.cfg.JcGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.api.jvm.ext.cfg.arrayRef -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.cfg.fieldRef - -class NullAnalysisMap : HashMap { - - constructor() : super() - constructor(m: Map) : super(m) - - override fun get(key: JcValue): NullableState { - return super.get(key) ?: NullableState.UNKNOWN - } -} - -/** - * An inter-procedural nullness assumption analysis that computes for each location and each value in a method if the value - * (before or after that location) is treated as definitely null, definitely non-null or neither. This information could be - * useful in deciding whether to insert code that accesses a potentially null object. - * - * If the original program assumes a value is non-null, then adding a use of that value will not introduce any NEW nullness - * errors into the program. This code may be buggy, or just plain wrong. It has not been checked. - */ -open class NullAssumptionAnalysis(graph: JcGraph) : BackwardFlowAnalysis(graph) { - - override val ins: MutableMap = HashMap() - override val outs: MutableMap = HashMap() - - override fun flowThrough( - instIn: NullAnalysisMap?, - ins: JcInst, - instOut: NullAnalysisMap, - ) { - val out = instIn?.let { NullAnalysisMap(it) } ?: NullAnalysisMap() - - // programmer assumes we have a non-null value - if (ins is JcEnterMonitorInst) { - out[ins.monitor] = NullableState.NON_NULL - } - - // if we have an array ref, set the info for this ref to TOP, - // because we need to be conservative here - ins.arrayRef?.let { - onArrayAccess(it, out) - } - // same for field refs, but also set the receiver object to non-null, if there is one - ins.fieldRef?.let { - onFieldRef(it, out) - } - // same for invoke expr., also set the receiver object to non-null, if there is one - ins.callExpr?.let { - onCallExpr(it, out) - } - - // allow sublasses to define certain values as always-non-null - for (entry in out.entries) { - if (isAlwaysNonNull(entry.key)) { - entry.setValue(NullableState.NON_NULL) - } - } - - // if we have a definition (assignment) statement to a ref-like type, handle it, - if (ins is JcAssignInst) { - // need to copy the current out set because we need to assign under this assumption; - // so this copy becomes the in-set to handleRefTypeAssignment - if (ins.lhv.type is JcRefType) { - onRefTypeAssignment(ins, NullAnalysisMap(out), out) - } - } - - // save memory by only retaining information about locals - val outIter = out.keys.iterator() - while (outIter.hasNext()) { - val v = outIter.next() - if (!(v is JcLocal)) { - outIter.remove() - } - } - - // now copy the computed info to out - copy(out, instOut) - } - - protected open fun isAlwaysNonNull(v: JcValue): Boolean { - return false - } - - private fun onArrayAccess(arrayRef: JcArrayAccess, out: NullAnalysisMap) { - // here we know that the array must point to an object, but the array value might be anything - out[arrayRef.array] = NullableState.NON_NULL - } - - private fun onFieldRef(fieldRef: JcFieldRef, out: NullAnalysisMap) { - // here we know that the receiver must point to an object - val instance = fieldRef.instance - if (instance != null) { - out[instance] = NullableState.NON_NULL - } - } - - private fun onCallExpr(invokeExpr: JcCallExpr, out: NullAnalysisMap) { - if (invokeExpr is JcInstanceCallExpr) { - // here we know that the receiver must point to an object - out[invokeExpr.instance] = NullableState.NON_NULL - } - } - - private fun onRefTypeAssignment(assignStmt: JcAssignInst, rhsInfo: NullAnalysisMap, out: NullAnalysisMap) { - val right = when (val rhv = assignStmt.rhv) { - is JcCastExpr -> rhv.operand - is JcValue -> rhv - else -> null - } - if (right != null) { - - // An assignment invalidates any assumptions of null/non-null for lhs - // We COULD be more accurate by assigning those assumptions to the rhs prior to this statement - rhsInfo[right] = NullableState.UNKNOWN - - // assign from rhs to lhs - out[assignStmt.lhv] = rhsInfo[right] - } - } - - override fun copy(source: NullAnalysisMap?, dest: NullAnalysisMap) { - dest.clear() - if (source != null) { - dest.putAll(source) - } - } - - override fun newEntryFlow(): NullAnalysisMap { - return NullAnalysisMap() - } - - override fun newFlow(): NullAnalysisMap { - return NullAnalysisMap() - } - - override fun merge(in1: NullAnalysisMap, in2: NullAnalysisMap, out: NullAnalysisMap) { - val values = HashSet() - values.addAll(in1.keys) - values.addAll(in2.keys) - out.clear() - for (v in values) { - val leftAndRight = HashSet() - leftAndRight.add(in1[v]) - leftAndRight.add(in2[v]) - val result = if (leftAndRight.contains(NullableState.UNKNOWN)) { - // if on either side we know nothing... then together we know nothing for sure - NullableState.UNKNOWN - } else if (leftAndRight.contains(NullableState.NON_NULL)) { - if (leftAndRight.contains(NullableState.NULL)) { - // NULL and NON_NULL merges to BOTTOM - NullableState.UNKNOWN - } else { - // NON_NULL and NON_NULL stays NON_NULL - NullableState.NON_NULL - } - } else if (leftAndRight.contains(NullableState.NULL)) { - // NULL and NULL stays NULL - NullableState.NULL - } else { - // only BOTTOM remains - NullableState.UNKNOWN - } - out[v] = result - } - } - - /** - * Returns `true` if the analysis could determine that `value` is always treated as null after and including the instruction inst. - * - * @param inst instruction of the respective body - * @param value a local or constant value of that body - * @return true if value is always null right before this statement - */ - fun isAssumedNullBefore(inst: JcInst, value: JcValue): Boolean { - return ins(inst)[value] == NullableState.NULL - } - - /** - * Returns `true` if the analysis could determine that value is always treated as non-null after and including the - * statement s. - * - * @param inst instruction of the respective body - * @param value a local or constant value of that body - * @return true if value is always non-null right before this statement - */ - fun isAssumedNonNullBefore(inst: JcInst, value: JcValue): Boolean { - return ins(inst)[value] == NullableState.NON_NULL - } - -} - -enum class NullableState { - UNKNOWN, - NULL, - NON_NULL -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt deleted file mode 100644 index 31a93398a..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcBasicBlock -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstRef -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.impl.cfg.JcBlockGraphImpl -import java.util.BitSet - -class ReachingDefinitionsAnalysis(val blockGraph: JcBlockGraphImpl) { - val jcGraph get() = blockGraph.jcGraph - - private val nDefinitions = jcGraph.instructions.size - private val ins = mutableMapOf() - private val outs = mutableMapOf() - private val assignmentsMap = mutableMapOf>() - - init { - initAssignmentsMap() - val entry = blockGraph.entry - for (block in blockGraph) - outs[block] = emptySet() - - val queue = ArrayDeque().also { it += entry } - val notVisited = blockGraph.toMutableSet() - while (queue.isNotEmpty() || notVisited.isNotEmpty()) { - val current = when { - queue.isNotEmpty() -> queue.removeFirst() - else -> notVisited.random() - } - notVisited -= current - - ins[current] = fullPredecessors(current).map { outs[it]!! }.fold(emptySet()) { acc, bitSet -> - acc.or(bitSet) - acc - } - - val oldOut = outs[current]!!.clone() as BitSet - val newOut = gen(current) - - if (oldOut != newOut) { - outs[current] = newOut - for (successor in fullSuccessors(current)) { - queue += successor - } - } - } - } - - private fun initAssignmentsMap() { - for (inst in jcGraph) { - if (inst is JcAssignInst) { - assignmentsMap.getOrPut(inst.lhv, ::mutableSetOf) += jcGraph.ref(inst) - } - } - } - - private fun emptySet(): BitSet = BitSet(nDefinitions) - - private fun gen(block: JcBasicBlock): BitSet { - val inSet = ins[block]!!.clone() as BitSet - for (inst in blockGraph.instructions(block)) { - if (inst is JcAssignInst) { - for (kill in assignmentsMap.getOrDefault(inst.lhv, mutableSetOf())) { - inSet[kill] = false - } - inSet[jcGraph.ref(inst)] = true - } - } - return inSet - } - - private fun fullPredecessors(block: JcBasicBlock) = blockGraph.predecessors(block) + blockGraph.throwers(block) - private fun fullSuccessors(block: JcBasicBlock) = blockGraph.successors(block) + blockGraph.catchers(block) - - private operator fun BitSet.set(ref: JcInstRef, value: Boolean) { - this.set(ref.index, value) - } - - fun outs(block: JcBasicBlock): List { - val defs = outs.getOrDefault(block, emptySet()) - return (0 until nDefinitions).filter { defs[it] }.map { jcGraph.instructions[it] } - } - -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt deleted file mode 100644 index aef9e63a7..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.npe - -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.taint.EdgeForOtherRunner -import org.jacodb.analysis.taint.NewSummaryEdge -import org.jacodb.analysis.taint.NewVulnerability -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintEdge -import org.jacodb.analysis.taint.TaintEvent -import org.jacodb.analysis.taint.TaintVertex -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.JcMethod -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class NpeAnalyzer( - private val graph: ApplicationGraph, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: ForwardNpeFlowFunctions by lazy { - ForwardNpeFlowFunctions(graph) - } - - private val taintConfigurationFeature: TaintConfigurationFeature? - get() = flowFunctions.taintConfigurationFeature - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) - } - - if (edge.to.fact is Tainted && edge.to.fact.mark == TaintMark.NULLNESS) { - if (edge.to.fact.variable.isDereferencedAt(edge.to.statement)) { - val message = "NPE" // TODO - val vulnerability = TaintVulnerability(message, sink = edge.to) - logger.info { - val m = graph.methodOf(vulnerability.sink.statement) - "Found sink=${vulnerability.sink} in $m" - } - add(NewVulnerability(vulnerability)) - } - } - - run { - val callExpr = edge.to.statement.getCallExpr() ?: return@run - val callee = callExpr.callee - - val config = taintConfigurationFeature?.let { feature -> - if (callee is JcMethod) { - logger.trace { "Extracting config for $callee" } - feature.getConfigForMethod(callee) - } else { - error("Cannot extract config for $callee") - } - } ?: return@run - - // TODO: not always we want to skip sinks on Zero facts. - // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - if (edge.to.fact !is Tainted) { - return@run - } - - // Determine whether 'edge.to' is a sink via config: - val conditionEvaluator = FactAwareConditionEvaluator( - edge.to.fact, - CallPositionToValueResolver(edge.to.statement), - ) - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - val message = item.ruleNote - val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) - logger.trace { - val m = graph.methodOf(vulnerability.sink.statement) - "Found sink=${vulnerability.sink} in $m on $item" - } - add(NewVulnerability(vulnerability)) - } - } - } - } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List> = buildList { - add(EdgeForOtherRunner(TaintEdge(callee, callee), Reason.CrossUnitCall(caller))) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt deleted file mode 100644 index c2144b76b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt +++ /dev/null @@ -1,665 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.npe - -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.CallPositionToAccessPathResolver -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.EntryPointPositionToAccessPathResolver -import org.jacodb.analysis.config.EntryPointPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.config.TaintActionEvaluator -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunction -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.isOnHeap -import org.jacodb.analysis.ifds.isStatic -import org.jacodb.analysis.ifds.minus -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.startsWith -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.JcArrayType -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcArgument -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcDynamicCallExpr -import org.jacodb.api.jvm.cfg.JcEqExpr -import org.jacodb.api.jvm.cfg.JcExpr -import org.jacodb.api.jvm.cfg.JcIfInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcNeqExpr -import org.jacodb.api.jvm.cfg.JcNewArrayExpr -import org.jacodb.api.jvm.cfg.JcNullConstant -import org.jacodb.api.jvm.cfg.JcReturnInst -import org.jacodb.api.jvm.ext.findType -import org.jacodb.impl.bytecode.isNullable -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.CopyMark -import org.jacodb.taint.configuration.RemoveAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.TaintCleaner -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintEntryPointSource -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class ForwardNpeFlowFunctions( - private val graph: ApplicationGraph, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - internal val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - if (graph is JcApplicationGraph) { - graph.cp.features - ?.singleOrNull { it is TaintConfigurationFeature } - ?.let { it as TaintConfigurationFeature } - } else { - null - } - } - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection = buildSet { - addAll(obtainPossibleStartFactsBasic(method)) - - // TODO: use common - if (method !is JcMethod) return@buildSet - - // Possibly null arguments: - for (p in method.parameters.filter { it.isNullable != false }) { - val t = (graph as JcApplicationGraph).cp.findType(p.type.typeName) - val arg = JcArgument.of(p.index, p.name, t) - val path = arg.toPath() - add(Tainted(path, TaintMark.NULLNESS)) - } - } - - private fun obtainPossibleStartFactsBasic( - method: Method, - ): Collection = buildSet { - // Zero (reachability) fact always present at entrypoint: - add(TaintZeroFact) - - // Extract initial facts from the config: - val config = taintConfigurationFeature?.let { feature -> - if (method is JcMethod) { - logger.trace { "Extracting config for $method" } - feature.getConfigForMethod(method) - } else { - error("Cannot extract config for $method") - } - } - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator(EntryPointPositionToValueResolver(method)) - val actionEvaluator = TaintActionEvaluator(EntryPointPositionToAccessPathResolver(method)) - - // Handle EntryPointSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { addAll(it) } - } - } - } - } - } - - private fun transmitTaintAssign( - fact: Tainted, - from: JcExpr, - to: CommonValue, - ): Collection { - val toPath = to.toPath() - val fromPath = from.toPathOrNull() - - if (fact.mark == TaintMark.NULLNESS) { - // TODO: consider - // if (from is JcNewExpr - // || from is JcNewArrayExpr - // || from is JcConstant - // || (from is JcCallExpr && from.method.method.isNullable != true)) - if (fact.variable.startsWith(toPath)) { - // NULLNESS is overridden: - return emptySet() - } - } - - if (fromPath != null) { - // Adhoc taint array: - if (fromPath.accesses.isNotEmpty() - && fromPath.accesses.last() is ElementAccessor - && fromPath == (fact.variable + ElementAccessor) - ) { - val newTaint = fact.copy(variable = toPath) - return setOf(fact, newTaint) - } - - val tail = fact.variable - fromPath - if (tail != null) { - // Both 'from' and 'to' are tainted now: - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - return setOf(fact, newTaint) - } - } - - return buildSet { - if (from is JcNullConstant) { - add(Tainted(toPath, TaintMark.NULLNESS)) - } - - if (fact.variable.startsWith(toPath)) { - // 'to' was (sub-)tainted, but it is now overridden by 'from': - return@buildSet - } else { - // Neither 'from' nor 'to' are tainted: - add(fact) - } - } - } - - private fun transmitTaintNormal( - fact: Tainted, - inst: Statement, - ): List { - // Pass-through: - return listOf(fact) - } - - private fun generates( - inst: Statement, - ): Collection = buildList { - if (inst is CommonAssignInst) { - val toPath = inst.lhv.toPath() - val from = inst.rhv - if (from is JcNullConstant || (from is JcCallExpr && from.method.method.isNullable == true)) { - add(Tainted(toPath, TaintMark.NULLNESS)) - } else if (from is JcNewArrayExpr && (from.type as JcArrayType).elementType.nullable != false) { - val accessors = List((from.type as JcArrayType).dimensions) { ElementAccessor } - val path = toPath + accessors - add(Tainted(path, TaintMark.NULLNESS)) - } - } - } - - private val JcIfInst.pathComparedWithNull: AccessPath? - get() { - val expr = condition - return if (expr.rhv is JcNullConstant) { - expr.lhv.toPathOrNull() - } else if (expr.lhv is JcNullConstant) { - expr.rhv.toPathOrNull() - } else { - null - } - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(current)) { - return@FlowFunction emptySet() - } - } - - if (current is JcIfInst) { - check(next is JcInst) - val nextIsTrueBranch = next.location.index == current.trueBranch.index - val pathComparedWithNull = current.pathComparedWithNull - if (fact == TaintZeroFact) { - if (pathComparedWithNull != null) { - if ((current.condition is JcEqExpr && nextIsTrueBranch) || - (current.condition is JcNeqExpr && !nextIsTrueBranch) - ) { - // This is a hack: instructions like `return null` in branch of next will be considered only if - // the fact holds (otherwise we could not get there) - // Note the absence of 'Zero' here! - return@FlowFunction listOf(Tainted(pathComparedWithNull, TaintMark.NULLNESS)) - } - } - } else if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - val expr = current.condition - if (pathComparedWithNull != fact.variable) { - return@FlowFunction listOf(fact) - } - if ((expr is JcEqExpr && nextIsTrueBranch) || (expr is JcNeqExpr && !nextIsTrueBranch)) { - // comparedPath is null in this branch - return@FlowFunction listOf(TaintZeroFact) - } else { - return@FlowFunction emptyList() - } - } - } - - if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + generates(current) - } - check(fact is Tainted) - - if (current is JcAssignInst) { - transmitTaintAssign(fact, from = current.rhv, to = current.lhv) - } else { - transmitTaintNormal(fact, current) - } - } - - private fun transmitTaint( - fact: Tainted, - at: Statement, - from: CommonValue, - to: CommonValue, - ): Collection = buildSet { - if (fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(at)) { - return@buildSet - } - } - - val fromPath = from.toPath() - val toPath = to.toPath() - - val tail = (fact.variable - fromPath) ?: return@buildSet - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - add(newTaint) - } - - private fun transmitTaintArgumentActualToFormal( - fact: Tainted, - at: Statement, - from: CommonValue, // actual - to: CommonValue, // formal - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintArgumentFormalToActual( - fact: Tainted, - at: Statement, - from: CommonValue, // formal - to: CommonValue, // actual - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintInstanceToThis( - fact: Tainted, - at: Statement, - from: CommonValue, // instance - to: CommonThis, // this - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintThisToInstance( - fact: Tainted, - at: Statement, - from: CommonThis, // this - to: CommonValue, // instance - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintReturn( - fact: Tainted, - at: Statement, - from: CommonValue, - to: CommonValue, - ): Collection = transmitTaint(fact, at, from, to) - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // FIXME: unused? - ) = FlowFunction { fact -> - if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(callStatement)) { - return@FlowFunction emptySet() - } - } - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - val callee = callExpr.callee - - // FIXME: handle taint pass-through on invokedynamic-based String concatenation: - if (fact is Tainted - && callExpr is JcDynamicCallExpr - && (callee as JcMethod).enclosingClass.name == "java.lang.invoke.StringConcatFactory" - && callStatement is JcAssignInst - ) { - for (arg in callExpr.args) { - if (arg.toPath() == fact.variable) { - return@FlowFunction setOf( - fact, - fact.copy(variable = callStatement.lhv.toPath()) - ) - } - } - return@FlowFunction setOf(fact) - } - - val config = taintConfigurationFeature?.let { feature -> - if (callee is JcMethod) { - logger.trace { "Extracting config for $callee" } - feature.getConfigForMethod(callee) - } else { - error("Cannot extract config for $callee") - } - } - - if (fact == TaintZeroFact) { - return@FlowFunction buildSet { - add(TaintZeroFact) - - if (callStatement is JcAssignInst) { - val toPath = callStatement.lhv.toPath() - val from = callStatement.rhv - if (from is JcNullConstant || (from is JcCallExpr && from.method.method.isNullable == true)) { - add(Tainted(toPath, TaintMark.NULLNESS)) - } else if (from is JcNewArrayExpr && (from.type as JcArrayType).elementType.nullable != false) { - val size = (from.type as JcArrayType).dimensions - val accessors = List(size) { ElementAccessor } - val path = toPath + accessors - add(Tainted(path, TaintMark.NULLNESS)) - } - } - - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator( - CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - - // Handle MethodSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { - addAll(it) - } - } - } - } - } - } - } - check(fact is Tainted) - - if (config != null) { - // FIXME: adhoc - if (callee is JcMethod - && callee.enclosingClass.name == "java.lang.StringBuilder" - && callee.name == "append" - ) { - // Skip rules for StringBuilder::append in NPE analysis. - } else { - val facts = mutableSetOf() - val conditionEvaluator = FactAwareConditionEvaluator( - fact, CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - var defaultBehavior = true - - // Handle PassThrough config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is CopyMark -> actionEvaluator.evaluate(action, fact) - is CopyAllMarks -> actionEvaluator.evaluate(action, fact) - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - // Handle Cleaner config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - if (!defaultBehavior) { - if (facts.size > 0) { - logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } - } - return@FlowFunction facts - } else { - // Fall back to the default behavior, as if there were no config at all. - } - } - } - - // FIXME: adhoc for constructors: - if (callee.isConstructor) { - return@FlowFunction listOf(fact) - } - - // TODO: CONSIDER REFACTORING THIS - // Default behavior for "analyzable" method calls is to remove ("temporarily") - // all the marks from the 'instance' and arguments, in order to allow them "pass through" - // the callee (when it is going to be analyzed), i.e. through "call-to-start" and - // "exit-to-return" flow functions. - // When we know that we are NOT going to analyze the callee, we do NOT need - // to remove any marks from 'instance' and arguments. - // Currently, "analyzability" of the callee depends on the fact that the callee - // is "accessible" through the JcApplicationGraph::callees(). - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return@FlowFunction emptyList() - } - - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - if (callExpr is JcInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - } - - if (callStatement is JcAssignInst) { - // Possibly tainted lhv: - if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by rhv - } - } - - // The "most default" behaviour is encapsulated here: - transmitTaintNormal(fact, callStatement) - } - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callee = graph.methodOf(calleeStart) - - if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFactsBasic(callee) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - buildSet { - // Transmit facts on arguments (from 'actual' to 'formal'): - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentActualToFormal( - fact = fact, - at = callStatement, - from = actual, - to = formal - ) - ) - } - - // Transmit facts on instance (from 'instance' to 'this'): - if (callExpr is JcInstanceCallExpr) { - addAll( - transmitTaintInstanceToThis( - fact = fact, - at = callStatement, - from = callExpr.instance, - to = callee.thisInstance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - } - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // unused - exitStatement: Statement, - ) = FlowFunction { fact -> - // TODO: do we even need to return non-empty list for zero fact here? - if (fact == TaintZeroFact) { - // return@FlowFunction listOf(Zero) - return@FlowFunction buildSet { - add(TaintZeroFact) - if (exitStatement is JcReturnInst && callStatement is JcAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - exitStatement.returnValue?.let { returnValue -> - if (returnValue is JcNullConstant) { - val toPath = callStatement.lhv.toPath() - add(Tainted(toPath, TaintMark.NULLNESS)) - } - } - } - } - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = graph.methodOf(exitStatement) - - buildSet { - // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: - if (fact.variable.isOnHeap) { - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentFormalToActual( - fact = fact, - at = callStatement, - from = formal, - to = actual - ) - ) - } - } - - // Transmit facts on instance (from 'this' to 'instance'): - if (callExpr is JcInstanceCallExpr) { - addAll( - transmitTaintThisToInstance( - fact = fact, - at = callStatement, - from = callee.thisInstance, - to = callExpr.instance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - - // Transmit facts on return value (from 'returnValue' to 'lhv'): - if (exitStatement is JcReturnInst && callStatement is JcAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - exitStatement.returnValue?.let { returnValue -> - addAll( - transmitTaintReturn( - fact = fact, - at = callStatement, - from = returnValue, - to = callStatement.lhv - ) - ) - } - } - } - } -} - -// TODO: class BackwardNpeFlowFunctions diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt deleted file mode 100644 index a9e52776d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.npe - -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintRunner -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class NpeManager( - graph: ApplicationGraph, - unitResolver: UnitResolver, -) : TaintManager(graph, unitResolver, useBidiRunner = false) - where Method : CommonMethod, - Statement : CommonInst { - - override fun newRunner( - unit: UnitType, - ): TaintRunner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - val analyzer = NpeAnalyzer(graph) - val runner = UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@NpeManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - - runnerForUnit[unit] = runner - return runner - } - - override fun addStart(method: Method) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - // Note: DO NOT add deps here! - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt deleted file mode 100644 index 05c07efac..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.npe - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.minus -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.startsWith -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcLengthExpr - -context(Traits) -internal fun AccessPath?.isDereferencedAt(expr: CommonExpr): Boolean { - if (this == null) { - return false - } - - if (expr is JcInstanceCallExpr) { - val instancePath = expr.instance.toPathOrNull() - if (instancePath.startsWith(this)) { - return true - } - } - - if (expr is JcLengthExpr) { - val arrayPath = expr.array.toPathOrNull() - if (arrayPath.startsWith(this)) { - return true - } - } - - return expr - .getValues() - .mapNotNull { it.toPathOrNull() } - .any { (it - this)?.isNotEmpty() == true } -} - -context(Traits) -internal fun AccessPath?.isDereferencedAt(inst: CommonInst): Boolean { - if (this == null) return false - return inst.getOperands().any { isDereferencedAt(it) } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt deleted file mode 100644 index 0746983d4..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.sarif - -import io.github.detekt.sarif4k.ArtifactLocation -import io.github.detekt.sarif4k.CodeFlow -import io.github.detekt.sarif4k.Location -import io.github.detekt.sarif4k.LogicalLocation -import io.github.detekt.sarif4k.Message -import io.github.detekt.sarif4k.MultiformatMessageString -import io.github.detekt.sarif4k.PhysicalLocation -import io.github.detekt.sarif4k.Region -import io.github.detekt.sarif4k.Result -import io.github.detekt.sarif4k.Run -import io.github.detekt.sarif4k.SarifSchema210 -import io.github.detekt.sarif4k.ThreadFlow -import io.github.detekt.sarif4k.ThreadFlowLocation -import io.github.detekt.sarif4k.Tool -import io.github.detekt.sarif4k.ToolComponent -import io.github.detekt.sarif4k.Version -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcInst - -private const val SARIF_SCHEMA = - "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" -private const val JACODB_INFORMATION_URI = - "https://github.com/UnitTestBot/jacodb/blob/develop/jacodb-analysis/README.md" -private const val DEFAULT_PATH_COUNT = 3 - -fun sarifReportFromVulnerabilities( - vulnerabilities: List>, - maxPathsCount: Int = DEFAULT_PATH_COUNT, - isDeduplicate: Boolean = true, - sourceFileResolver: SourceFileResolver = SourceFileResolver { null }, -): SarifSchema210 { - return SarifSchema210( - schema = SARIF_SCHEMA, - version = Version.The210, - runs = listOf( - Run( - tool = Tool( - driver = ToolComponent( - name = "jacodb-analysis", - organization = "UnitTestBot", - version = "1.4.5", - informationURI = JACODB_INFORMATION_URI, - ) - ), - results = vulnerabilities.map { instance -> - Result( - ruleID = instance.description.ruleId, - message = Message( - text = instance.description.message - ), - level = instance.description.level, - locations = listOfNotNull( - instToSarifLocation( - instance.traceGraph.sink.statement, - sourceFileResolver - ) - ), - codeFlows = instance.traceGraph - .getAllTraces() - .take(maxPathsCount) - .map { traceToSarifCodeFlow(it, sourceFileResolver, isDeduplicate) } - .toList(), - ) - } - ) - ) - ) -} - -private fun instToSarifLocation( - inst: Statement, - sourceFileResolver: SourceFileResolver, -): Location? { - val sourceLocation = sourceFileResolver.resolve(inst) ?: return null - return Location( - physicalLocation = PhysicalLocation( - artifactLocation = ArtifactLocation( - uri = sourceLocation - ), - region = Region( - startLine = if (inst is JcInst) inst.location.lineNumber.toLong() else null, - ) - ), - logicalLocations = listOf( - LogicalLocation( - fullyQualifiedName = if (inst is JcInst) { - val method = inst.location.method - "${method.enclosingClass.name}#${method.name}" - } else { - null - } - ) - ) - ) -} - -private fun traceToSarifCodeFlow( - trace: List>, - sourceFileResolver: SourceFileResolver, - isDeduplicate: Boolean = true, -): CodeFlow { - return CodeFlow( - threadFlows = listOf( - ThreadFlow( - locations = trace.map { - ThreadFlowLocation( - location = instToSarifLocation(it.statement, sourceFileResolver), - state = mapOf( - "fact" to MultiformatMessageString( - text = it.fact.toString() - ) - ) - ) - }.let { - if (isDeduplicate) it.deduplicate() else it - } - ) - ) - ) -} - -private fun List.deduplicate(): List { - if (isEmpty()) return emptyList() - - return listOf(first()) + zipWithNext { a, b -> - val aLine = a.location?.physicalLocation?.region?.startLine - val bLine = b.location?.physicalLocation?.region?.startLine - if (aLine != bLine) { - b - } else { - null - } - }.filterNotNull() -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt deleted file mode 100644 index 089b97784..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.sarif - -import org.jacodb.api.common.cfg.CommonInst - -fun interface SourceFileResolver { - fun resolve(inst: Statement): String? -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt deleted file mode 100644 index 576f4b0f4..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.sarif - -import io.github.detekt.sarif4k.Level -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.api.common.cfg.CommonInst - -data class VulnerabilityInstance( - val traceGraph: TraceGraph, - val description: VulnerabilityDescription, -) - -data class VulnerabilityDescription( - val ruleId: String?, - val message: String?, - val level: Level = Level.Warning, -) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt deleted file mode 100644 index 97a7541c3..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.sarif.VulnerabilityDescription -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.api.common.cfg.CommonInst - -fun TaintVulnerability.toSarif( - graph: TraceGraph, -): VulnerabilityInstance = - VulnerabilityInstance( - graph, - VulnerabilityDescription( - ruleId = null, - message = rule?.ruleNote - ) - ) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt deleted file mode 100644 index 61ce97425..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -object TaintAnalysisOptions { - var UNTRUSTED_LOOP_BOUND_SINK = false - var UNTRUSTED_ARRAY_SIZE_SINK = false - var UNTRUSTED_INDEX_ARRAY_ACCESS_SINK = false -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt deleted file mode 100644 index 675c9c2a1..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.toPath -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcIfInst -import org.jacodb.impl.cfg.util.loops -import org.jacodb.ets.base.EtsArrayAccess -import org.jacodb.ets.base.EtsAssignStmt -import org.jacodb.ets.base.EtsIfStmt -import org.jacodb.ets.base.EtsNewArrayExpr -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.loops -import org.jacodb.ets.utils.getOperands -import org.jacodb.panda.staticvm.utils.loops -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.panda.staticvm.cfg.PandaIfInst as StaticPandaIfInst - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class TaintAnalyzer( - private val graph: ApplicationGraph, - private val getConfigForMethod: (ForwardTaintFlowFunctions.(Method) -> List?)? = null, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: ForwardTaintFlowFunctions by lazy { - if (getConfigForMethod != null) { - ForwardTaintFlowFunctions(graph, getConfigForMethod) - } else { - ForwardTaintFlowFunctions(graph) - } - } - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) - } - - run { - val callExpr = edge.to.statement.getCallExpr() ?: return@run - - val callee = callExpr.callee - - val config = with(flowFunctions) { getConfigForMethod(callee) } ?: return@run - - // TODO: not always we want to skip sinks on Zero facts. - // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - if (edge.to.fact !is Tainted) { - return@run - } - - // Determine whether 'edge.to' is a sink via config: - val conditionEvaluator = FactAwareConditionEvaluator( - edge.to.fact, - CallPositionToValueResolver(edge.to.statement), - ) - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - val message = item.ruleNote - val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) - logger.info { - "Found sink=${vulnerability.sink} in ${vulnerability.method} on $item" - } - add(NewVulnerability(vulnerability)) - } - } - } - - if (TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK) { - val statement = edge.to.statement - val fact = edge.to.fact - if (fact is Tainted && fact.mark.name == "UNTRUSTED") { - if (statement is JcIfInst) { - val loops = statement.location.method.flowGraph().loops - val loopHeads = loops.map { it.head } - if (statement in loopHeads) { - for (s in statement.condition.operands) { - val p = s.toPath() - if (p == fact.variable) { - val message = "Untrusted loop bound" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } else if (statement is StaticPandaIfInst) { - val loops = statement.location.method.flowGraph().loops - if (loops.any { statement in it.instructions }) { - for (s in statement.condition.operands) { - val p = s.toPath() - if (p == fact.variable) { - val message = "Untrusted loop bound" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } else if (statement is EtsIfStmt) { - val pandaGraph = statement.location.method.flowGraph() - val loops = pandaGraph.loops - if (loops.any { statement in it.instructions }) { - for (s in statement.condition.getOperands()) { - val p = s.toPath() - if (p == fact.variable) { - val message = "Untrusted loop bound" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } - } - } - if (TaintAnalysisOptions.UNTRUSTED_ARRAY_SIZE_SINK) { - val statement = edge.to.statement - val fact = edge.to.fact - if (fact is Tainted && fact.mark.name == "UNTRUSTED") { - if (statement is EtsAssignStmt) { - val expr = statement.rhv - if (expr is EtsNewArrayExpr) { - val arg = expr.size - if (arg.toPathOrNull() == fact.variable) { - val message = "Untrusted array size" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } - } - if (TaintAnalysisOptions.UNTRUSTED_INDEX_ARRAY_ACCESS_SINK) { - val statement = edge.to.statement - val fact = edge.to.fact - if (fact is Tainted && fact.mark.name == "UNTRUSTED") { - if (statement is EtsStmt) { - for (op in statement.getOperands()) { - if (op is EtsArrayAccess) { - val arg = op.index - if (arg.toPathOrNull() == fact.variable) { - val message = "Untrusted index for access array" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } - } - } - } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List> = buildList { - add(EdgeForOtherRunner(TaintEdge(callee, callee), Reason.CrossUnitCall(caller))) - } -} - -context(Traits) -class BackwardTaintAnalyzer( - private val graph: ApplicationGraph, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: BackwardTaintFlowFunctions by lazy { - BackwardTaintFlowFunctions(graph) - } - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(EdgeForOtherRunner(Edge(edge.to, edge.to), reason = Reason.External)) - } - } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List> { - return emptyList() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt deleted file mode 100644 index f21a41da2..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.IfdsResult -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst - -class TaintBidiRunner( - val manager: TaintManager, - override val graph: ApplicationGraph, - val unitResolver: UnitResolver, - override val unit: UnitType, - newForwardRunner: (Manager, Method, Statement>) -> TaintRunner, - newBackwardRunner: (Manager, Method, Statement>) -> TaintRunner, -) : TaintRunner - where Method : CommonMethod, - Statement : CommonInst { - - @Volatile - private var forwardQueueIsEmpty: Boolean = false - - @Volatile - private var backwardQueueIsEmpty: Boolean = false - - private val forwardManager: Manager, Method, Statement> = - object : Manager, Method, Statement> { - override fun handleEvent(event: TaintEvent) { - when (event) { - is EdgeForOtherRunner -> { - val m = graph.methodOf(event.edge.from.statement) - if (unitResolver.resolve(m) == unit) { - // Submit new edge directly to the backward runner: - backwardRunner.submitNewEdge(event.edge, event.reason) - } else { - // Submit new edge via the manager: - manager.handleEvent(event) - } - } - - else -> manager.handleEvent(event) - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - forwardQueueIsEmpty = event.isEmpty - val newEvent = QueueEmptinessChanged(event.runner, forwardQueueIsEmpty && backwardQueueIsEmpty) - manager.handleControlEvent(newEvent) - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - manager.subscribeOnSummaryEdges(method, scope, handler) - } - } - - private val backwardManager: Manager, Method, Statement> = - object : Manager, Method, Statement> { - override fun handleEvent(event: TaintEvent) { - when (event) { - is EdgeForOtherRunner -> { - val m = graph.methodOf(event.edge.from.statement) - check(unitResolver.resolve(m) == unit) - // Submit new edge directly to the forward runner: - forwardRunner.submitNewEdge(event.edge, event.reason) - } - - else -> manager.handleEvent(event) - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - backwardQueueIsEmpty = event.isEmpty - val newEvent = QueueEmptinessChanged(event.runner, forwardQueueIsEmpty && backwardQueueIsEmpty) - manager.handleControlEvent(newEvent) - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - // TODO: ignore? - manager.subscribeOnSummaryEdges(method, scope, handler) - } - } - - val forwardRunner: TaintRunner = newForwardRunner(forwardManager) - val backwardRunner: TaintRunner = newBackwardRunner(backwardManager) - - init { - check(forwardRunner.unit == unit) - check(backwardRunner.unit == unit) - } - - override fun submitNewEdge( - edge: Edge, - reason: Reason, - ) { - forwardRunner.submitNewEdge(edge, reason) - } - - override suspend fun run(startMethods: List) = coroutineScope { - val backwardRunnerJob = launch(start = CoroutineStart.LAZY) { backwardRunner.run(startMethods) } - val forwardRunnerJob = launch(start = CoroutineStart.LAZY) { forwardRunner.run(startMethods) } - - backwardRunnerJob.start() - forwardRunnerJob.start() - - backwardRunnerJob.join() - forwardRunnerJob.join() - } - - override fun getIfdsResult(): IfdsResult { - return forwardRunner.getIfdsResult() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt deleted file mode 100644 index 47c12fb44..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.Reason -import org.jacodb.api.common.cfg.CommonInst - -sealed interface TaintEvent - -data class NewSummaryEdge( - val edge: TaintEdge, -) : TaintEvent - -data class NewVulnerability( - val vulnerability: TaintVulnerability, -) : TaintEvent - -data class EdgeForOtherRunner( - val edge: TaintEdge, - val reason: Reason, -) : TaintEvent { - init { - // TODO: remove this check - check(edge.from == edge.to) { "Edge for another runner must be a loop" } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt deleted file mode 100644 index 0fec8b62c..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.taint.configuration.TaintMark - -sealed interface TaintDomainFact - -object TaintZeroFact : TaintDomainFact { - override fun toString(): String = "Zero" -} - -data class Tainted( - val variable: AccessPath, - val mark: TaintMark, -) : TaintDomainFact diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt deleted file mode 100644 index f028b72be..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.CallPositionToAccessPathResolver -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.EntryPointPositionToAccessPathResolver -import org.jacodb.analysis.config.EntryPointPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.config.TaintActionEvaluator -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunction -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.isOnHeap -import org.jacodb.analysis.ifds.isStatic -import org.jacodb.analysis.ifds.minus -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.startsWith -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonInstanceCallExpr -import org.jacodb.api.common.cfg.CommonReturnInst -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcBinaryExpr -import org.jacodb.api.jvm.cfg.JcCastExpr -import org.jacodb.api.jvm.cfg.JcDynamicCallExpr -import org.jacodb.api.jvm.cfg.JcNegExpr -import org.jacodb.ets.base.EtsBinaryExpr -import org.jacodb.ets.base.EtsCastExpr -import org.jacodb.ets.base.EtsUnaryExpr -import org.jacodb.ets.utils.getOperands -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.CopyMark -import org.jacodb.taint.configuration.RemoveAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.TaintCleaner -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintEntryPointSource -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.jacodb.panda.staticvm.cfg.PandaBinaryExpr as StaticPandaBinaryExpr -import org.jacodb.panda.staticvm.cfg.PandaCastExpr as StaticPandaCastExpr -import org.jacodb.panda.staticvm.cfg.PandaNegExpr as StaticPandaNegExpr -import org.jacodb.panda.staticvm.cfg.PandaNotExpr as StaticPandaNotExpr -import org.jacodb.panda.staticvm.cfg.PandaPhiExpr as StaticPandaPhiExpr -import org.jacodb.panda.staticvm.cfg.PandaPhiInst as StaticPandaPhiInst - -private val logger = mu.KotlinLogging.logger {} - -// TODO: replace with CommonMethod, with CommonInst -context(Traits) -class ForwardTaintFlowFunctions( - private val graph: ApplicationGraph, - val getConfigForMethod: ForwardTaintFlowFunctions.(Method) -> List? = { method -> - taintConfigurationFeature?.let { feature -> - if (method is JcMethod) { - logger.trace { "Extracting config for $method" } - feature.getConfigForMethod(method) - } else { - error("Cannot extract config for $method") - } - } - }, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - // // TODO: inline - // private fun CommonExpr.toPathOrNull(): AccessPath? = traits.toPathOrNull(this) - // private fun CommonValue.toPath(): AccessPath = traits.toPath(this) - - private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - if (graph is JcApplicationGraph) { - graph.cp.features - ?.singleOrNull { it is TaintConfigurationFeature } - ?.let { it as TaintConfigurationFeature } - } else { - null - } - } - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection = buildSet { - // Zero (reachability) fact always present at entrypoint: - add(TaintZeroFact) - - // Extract initial facts from the config: - val config = getConfigForMethod(method) - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator( - EntryPointPositionToValueResolver(method) - ) - val actionEvaluator = TaintActionEvaluator( - EntryPointPositionToAccessPathResolver(method) - ) - - // Handle EntryPointSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { addAll(it) } - } - } - } - } - } - - private fun transmitTaintAssign( - fact: Tainted, - from: CommonExpr, - to: CommonValue, - ): Collection { - val toPath = to.toPath() - val fromPath = from.toPathOrNull() - - if (fromPath != null) { - // Adhoc taint array: - if (fromPath.accesses.isNotEmpty() - && fromPath.accesses.last() is ElementAccessor - && fromPath == (fact.variable + ElementAccessor) - ) { - val newTaint = fact.copy(variable = toPath) - return setOf(fact, newTaint) - } - - val tail = fact.variable - fromPath - if (tail != null) { - // Both 'from' and 'to' are tainted now: - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - return setOf(fact, newTaint) - } - } - - if (fact.variable.startsWith(toPath)) { - // 'to' was (sub-)tainted, but it is now overridden by 'from': - return emptySet() - } else { - // Neither 'from' nor 'to' are tainted: - return setOf(fact) - } - } - - private fun transmitTaintNormal( - fact: Tainted, - inst: Statement, - ): List { - // Pass-through: - return listOf(fact) - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - if (current is CommonAssignInst) { - when (val rhv = current.rhv) { - is StaticPandaPhiExpr -> { - val facts: MutableSet = mutableSetOf() - for (input in rhv.inputs) { - facts += transmitTaintAssign(fact, from = input, to = current.lhv) - } - // For empty phi, pass-through: - val pass = transmitTaintNormal(fact, current) - facts + pass - } - - is JcBinaryExpr -> { - val facts: MutableSet = mutableSetOf() - facts += transmitTaintAssign(fact, from = rhv.lhv, to = current.lhv) - facts += transmitTaintAssign(fact, from = rhv.rhv, to = current.lhv) - facts - } - - is JcNegExpr -> { - transmitTaintAssign(fact, from = rhv.operand, to = current.lhv) - } - - is JcCastExpr -> { - transmitTaintAssign(fact, from = rhv.operand, to = current.lhv) - } - - is StaticPandaBinaryExpr -> { - val facts: MutableSet = mutableSetOf() - facts += transmitTaintAssign(fact, from = rhv.lhv, to = current.lhv) - facts += transmitTaintAssign(fact, from = rhv.rhv, to = current.lhv) - facts - } - - is EtsBinaryExpr -> { - val facts: MutableSet = mutableSetOf() - facts += transmitTaintAssign(fact, from = rhv.left, to = current.lhv) - facts += transmitTaintAssign(fact, from = rhv.right, to = current.lhv) - facts - } - - is StaticPandaNegExpr -> { - transmitTaintAssign(fact, from = rhv.arg, to = current.lhv) - } - - is EtsUnaryExpr -> { - transmitTaintAssign(fact, from = rhv.getOperands().first(), to = current.lhv) - } - - is StaticPandaNotExpr -> { - transmitTaintAssign(fact, from = rhv.arg, to = current.lhv) - } - - is StaticPandaCastExpr -> { - transmitTaintAssign(fact, from = rhv.arg, to = current.lhv) - } - - is EtsCastExpr -> { - transmitTaintAssign(fact, from = rhv.getOperands().first(), to = current.lhv) - } - - else -> { - transmitTaintAssign(fact, from = current.rhv, to = current.lhv) - } - } - } else if (current is StaticPandaPhiInst) { - val facts: MutableSet = mutableSetOf() - for (input in current.inputs) { - facts += transmitTaintAssign(fact, from = input, to = current.lhv) - } - // For empty phi, pass-through: - val pass = transmitTaintNormal(fact, current) - facts + pass - } else { - transmitTaintNormal(fact, current) - } - } - - private fun transmitTaint( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = buildSet { - val fromPath = from.toPath() - val toPath = to.toPath() - - val tail = (fact.variable - fromPath) ?: return@buildSet - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - add(newTaint) - } - - private fun transmitTaintArgumentActualToFormal( - fact: Tainted, - from: CommonValue, // actual - to: CommonValue, // formal - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintArgumentFormalToActual( - fact: Tainted, - from: CommonValue, // formal - to: CommonValue, // actual - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintInstanceToThis( - fact: Tainted, - from: CommonValue, // instance - to: CommonThis, // this - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintThisToInstance( - fact: Tainted, - from: CommonThis, // this - to: CommonValue, // instance - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintReturn( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = transmitTaint(fact, from, to) - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // FIXME: unused? - ) = FlowFunction { fact -> - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - val callee = callExpr.callee - - // FIXME: handle taint pass-through on invokedynamic-based String concatenation: - if (fact is Tainted - && callExpr is JcDynamicCallExpr - && (callee as JcMethod).enclosingClass.name == "java.lang.invoke.StringConcatFactory" - && callStatement is JcAssignInst - ) { - for (arg in callExpr.args) { - if (arg.toPath() == fact.variable) { - return@FlowFunction setOf( - fact, - fact.copy(variable = callStatement.lhv.toPath()) - ) - } - } - return@FlowFunction setOf(fact) - } - - val config = getConfigForMethod(callee) - - if (fact == TaintZeroFact) { - return@FlowFunction buildSet { - add(TaintZeroFact) - - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator( - CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - - // Handle MethodSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { addAll(it) } - } - } - } - } - } - } - check(fact is Tainted) - - if (config != null) { - val facts = mutableSetOf() - val conditionEvaluator = FactAwareConditionEvaluator( - fact, CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - var defaultBehavior = true - - // Handle PassThrough config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is CopyMark -> actionEvaluator.evaluate(action, fact) - is CopyAllMarks -> actionEvaluator.evaluate(action, fact) - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - // Handle Cleaner config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - if (!defaultBehavior) { - if (facts.size > 0) { - logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } - } - return@FlowFunction facts - } else { - // Fall back to the default behavior, as if there were no config at all. - } - } - - // FIXME: adhoc for constructors: - if (callee.isConstructor) { - return@FlowFunction listOf(fact) - } - - // TODO: CONSIDER REFACTORING THIS - // Default behavior for "analyzable" method calls is to remove ("temporarily") - // all the marks from the 'instance' and arguments, in order to allow them "pass through" - // the callee (when it is going to be analyzed), i.e. through "call-to-start" and - // "exit-to-return" flow functions. - // When we know that we are NOT going to analyze the callee, we do NOT need - // to remove any marks from 'instance' and arguments. - // Currently, "analyzability" of the callee depends on the fact that the callee - // is "accessible" through the JcApplicationGraph::callees(). - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return@FlowFunction emptyList() - } - - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - if (callExpr is CommonInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - } - - if (callStatement is CommonAssignInst) { - // Possibly tainted lhv: - if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by rhv - } - } - - // The "most default" behaviour is encapsulated here: - transmitTaintNormal(fact, callStatement) - } - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callee = graph.methodOf(calleeStart) - - if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFacts(callee) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - buildSet { - // Transmit facts on arguments (from 'actual' to 'formal'): - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll(transmitTaintArgumentActualToFormal(fact, from = actual, to = formal)) - } - - // Transmit facts on instance (from 'instance' to 'this'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintInstanceToThis( - fact = fact, - from = callExpr.instance, - to = callee.thisInstance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - } - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // unused - exitStatement: Statement, - ) = FlowFunction { fact -> - if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = graph.methodOf(exitStatement) - - buildSet { - // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: - if (fact.variable.isOnHeap) { - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentFormalToActual( - fact = fact, - from = formal, - to = actual - ) - ) - } - } - - // Transmit facts on instance (from 'this' to 'instance'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintThisToInstance( - fact = fact, - from = callee.thisInstance, - to = callExpr.instance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - - // Transmit facts on return value (from 'returnValue' to 'lhv'): - if (exitStatement is CommonReturnInst && callStatement is CommonAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - exitStatement.returnValue?.let { returnValue -> - addAll(transmitTaintReturn(fact, from = returnValue, to = callStatement.lhv)) - } - } - } - } -} - -context(Traits) -class BackwardTaintFlowFunctions( - private val graph: ApplicationGraph, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection { - return listOf(TaintZeroFact) - } - - private fun transmitTaintBackwardAssign( - fact: Tainted, - from: CommonValue, - to: CommonExpr, - ): Collection { - val fromPath = from.toPath() - val toPath = to.toPathOrNull() - - if (toPath != null) { - val tail = fact.variable - fromPath - if (tail != null) { - // Both 'from' and 'to' are tainted now: - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - return setOf(fact, newTaint) - } - - if (fact.variable.startsWith(toPath)) { - // 'to' was (sub-)tainted, but it is now overridden by 'from': - return emptySet() - } - } - - // Pass-through: - return setOf(fact) - } - - private fun transmitTaintBackwardNormal( - fact: Tainted, - inst: Statement, - ): List { - // Pass-through: - return listOf(fact) - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - if (current is CommonAssignInst) { - transmitTaintBackwardAssign(fact, from = current.lhv, to = current.rhv) - } else { - transmitTaintBackwardNormal(fact, current) - } - } - - private fun transmitTaint( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = buildSet { - val fromPath = from.toPath() - val toPath = to.toPath() - - val tail = (fact.variable - fromPath) ?: return@buildSet - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - add(newTaint) - } - - private fun transmitTaintArgumentActualToFormal( - fact: Tainted, - from: CommonValue, // actual - to: CommonValue, // formal - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintArgumentFormalToActual( - fact: Tainted, - from: CommonValue, // formal - to: CommonValue, // actual - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintInstanceToThis( - fact: Tainted, - from: CommonValue, // instance - to: CommonThis, // this - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintThisToInstance( - fact: Tainted, - from: CommonThis, // this - to: CommonValue, // instance - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintReturn( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = transmitTaint(fact, from, to) - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // FIXME: unused? - ) = FlowFunction { fact -> - // TODO: pass-through on invokedynamic-based String concatenation - - if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = callExpr.callee - - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return@FlowFunction emptyList() - } - - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - if (callExpr is CommonInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - } - - if (callStatement is CommonAssignInst) { - // Possibly tainted rhv: - if (fact.variable.startsWith(callStatement.rhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by lhv - } - } - - // The "most default" behaviour is encapsulated here: - transmitTaintBackwardNormal(fact, callStatement) - } - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callee = graph.methodOf(calleeStart) - - if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFacts(callee) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - buildSet { - // Transmit facts on arguments (from 'actual' to 'formal'): - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll(transmitTaintArgumentActualToFormal(fact, from = actual, to = formal)) - } - - // Transmit facts on instance (from 'instance' to 'this'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintInstanceToThis( - fact = fact, - from = callExpr.instance, - to = callee.thisInstance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - - // Transmit facts on return value (from 'returnValue' to 'lhv'): - if (calleeStart is CommonReturnInst && callStatement is CommonAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - calleeStart.returnValue?.let { returnValue -> - addAll( - transmitTaintReturn( - fact = fact, - from = callStatement.lhv, - to = returnValue - ) - ) - } - } - } - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - exitStatement: Statement, - ) = FlowFunction { fact -> - if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = graph.methodOf(exitStatement) - - buildSet { - // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: - if (fact.variable.isOnHeap) { - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentFormalToActual( - fact = fact, - from = formal, - to = actual - ) - ) - } - } - - // Transmit facts on instance (from 'this' to 'instance'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintThisToInstance( - fact = fact, - from = callee.thisInstance, - to = callExpr.instance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt deleted file mode 100644 index 641092696..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeoutOrNull -import org.jacodb.analysis.graph.reversed -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.IfdsResult -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.SummaryStorageImpl -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.taint.configuration.TaintConfigurationItem -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -open class TaintManager( - protected val graph: ApplicationGraph, - protected val unitResolver: UnitResolver, - private val useBidiRunner: Boolean = false, - private val getConfigForMethod: (ForwardTaintFlowFunctions.(Method) -> List?)? = null, -) : Manager, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - protected val methodsForUnit: MutableMap> = hashMapOf() - val runnerForUnit: MutableMap> = hashMapOf() - private val queueIsEmpty = ConcurrentHashMap() - - private val summaryEdgesStorage = SummaryStorageImpl>() - private val vulnerabilitiesStorage = SummaryStorageImpl>() - - private val stopRendezvous = Channel(Channel.RENDEZVOUS) - - protected open fun newRunner( - unit: UnitType, - ): TaintRunner { - // check(unit !in runnerForUnit) { "Runner for $unit already exists" } - if (unit in runnerForUnit) { - return runnerForUnit[unit]!! - } - - logger.debug { "Creating a new runner for $unit" } - val runner = if (useBidiRunner) { - TaintBidiRunner( - manager = this@TaintManager, - graph = graph, - unitResolver = unitResolver, - unit = unit, - { manager -> - val analyzer = TaintAnalyzer(graph, getConfigForMethod) - UniRunner( - manager = manager, - graph = graph, - analyzer = analyzer, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - }, - { manager -> - val analyzer = BackwardTaintAnalyzer(graph) - UniRunner( - manager = manager, - graph = graph.reversed, - analyzer = analyzer, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - } - ) - } else { - val analyzer = TaintAnalyzer(graph, getConfigForMethod) - UniRunner( - manager = this@TaintManager, - graph = graph, - analyzer = analyzer, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - } - - runnerForUnit[unit] = runner - return runner - } - - private fun getAllCallees(method: Method): Set { - val result: MutableSet = hashSetOf() - for (inst in method.flowGraph().instructions) { - @Suppress("UNCHECKED_CAST") - result += graph.callees(inst as Statement) - } - return result - } - - protected open fun addStart(method: Method) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - val isNew = methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - if (isNew) { - for (dep in getAllCallees(method)) { - addStart(dep) - } - } - } - - @JvmName("analyze") // needed for Java interop because of inline class (Duration) - @OptIn(ExperimentalTime::class) - fun analyze( - startMethods: List, - timeout: Duration = 3600.seconds, - ): List> = runBlocking(Dispatchers.Default) { - val timeStart = TimeSource.Monotonic.markNow() - - // Add start methods: - for (method in startMethods) { - addStart(method) - } - - // Determine all units: - val allUnits = methodsForUnit.keys.toList() - logger.info { - "Starting analysis of ${ - methodsForUnit.values.sumOf { it.size } - } methods in ${allUnits.size} units" - } - - // Spawn runner jobs: - val allJobs = allUnits.map { unit -> - // Create the runner: - val runner = newRunner(unit) - - // Start the runner: - launch(start = CoroutineStart.LAZY) { - val methods = methodsForUnit[unit]!!.toList() - runner.run(methods) - } - } - - // Spawn progress job: - val progress = launch(Dispatchers.IO) { - while (isActive) { - delay(1.seconds) - logger.info { - "Progress: propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - } - } - - // Spawn stopper job: - val stopper = launch(Dispatchers.IO) { - stopRendezvous.receive() - logger.info { "Stopping all runners..." } - allJobs.forEach { it.cancel() } - } - - // Start all runner jobs: - val timeStartJobs = TimeSource.Monotonic.markNow() - allJobs.forEach { it.start() } - - // Await all runners: - withTimeoutOrNull(timeout) { - allJobs.joinAll() - } ?: run { - logger.info { "Timeout!" } - allJobs.forEach { it.cancel() } - allJobs.joinAll() - } - progress.cancelAndJoin() - stopper.cancelAndJoin() - logger.info { - "All ${allJobs.size} jobs completed in %.1f s".format( - timeStartJobs.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - - // Extract found vulnerabilities (sinks): - val foundVulnerabilities = vulnerabilitiesStorage.knownMethods - .flatMap { method -> - vulnerabilitiesStorage.getCurrentFacts(method) - } - if (logger.isDebugEnabled) { - logger.debug { "Total found ${foundVulnerabilities.size} vulnerabilities" } - for (vulnerability in foundVulnerabilities) { - logger.debug { "$vulnerability in ${vulnerability.method}" } - } - } - logger.info { "Total sinks: ${foundVulnerabilities.size}" } - logger.info { - "Total propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - logger.info { - "Analysis done in %.1f s".format( - timeStart.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - foundVulnerabilities - } - - override fun handleEvent(event: TaintEvent) { - when (event) { - is NewSummaryEdge -> { - summaryEdgesStorage.add(TaintSummaryEdge(event.edge)) - } - - is NewVulnerability -> { - vulnerabilitiesStorage.add(event.vulnerability) - } - - is EdgeForOtherRunner -> { - val method = graph.methodOf(event.edge.from.statement) - val unit = unitResolver.resolve(method) - val otherRunner = runnerForUnit[unit] ?: run { - // error("No runner for $unit") - logger.trace { "Ignoring event=$event for non-existing runner for unit=$unit" } - return - } - otherRunner.submitNewEdge(event.edge, event.reason) - } - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - queueIsEmpty[event.runner.unit] = event.isEmpty - if (event.isEmpty) { - if (runnerForUnit.keys.all { queueIsEmpty[it] == true }) { - logger.debug { "All runners are empty" } - stopRendezvous.trySend(Unit).getOrNull() - } - } - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - summaryEdgesStorage - .getFacts(method) - .onEach { handler(it.edge) } - .launchIn(scope) - } - - fun vulnerabilityTraceGraph( - vulnerability: TaintVulnerability, - ): TraceGraph { - @Suppress("UNCHECKED_CAST") - val result = getIfdsResultForMethod(vulnerability.method as Method) - val initialGraph = result.buildTraceGraph(vulnerability.sink) - val resultGraph = initialGraph.copy(unresolvedCrossUnitCalls = emptyMap()) - - val resolvedCrossUnitEdges = - hashSetOf, Vertex>>() - val unresolvedCrossUnitCalls = initialGraph.unresolvedCrossUnitCalls.entries.toMutableList() - while (unresolvedCrossUnitCalls.isNotEmpty()) { - val (caller, callees) = unresolvedCrossUnitCalls.removeLast() - - val unresolvedCallees = hashSetOf>() - for (callee in callees) { - if (resolvedCrossUnitEdges.add(caller to callee)) { - unresolvedCallees.add(callee) - } - } - - if (unresolvedCallees.isEmpty()) continue - - @Suppress("UNCHECKED_CAST") - val callerResult = getIfdsResultForMethod(caller.method as Method) - val callerGraph = callerResult.buildTraceGraph(caller) - resultGraph.mergeWithUpGraph(callerGraph, unresolvedCallees) - unresolvedCrossUnitCalls += callerGraph.unresolvedCrossUnitCalls.entries - } - - return resultGraph - } - - private fun getIfdsResultForMethod(method: Method): IfdsResult { - val unit = unitResolver.resolve(method) - val runner = runnerForUnit[unit] ?: error("No runner for $unit") - return runner.getIfdsResult() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt deleted file mode 100644 index a97a03af8..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.SummaryEdge -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.taint.configuration.TaintMethodSink - -data class TaintSummaryEdge( - override val edge: TaintEdge, -) : SummaryEdge - -data class TaintVulnerability( - override val message: String, - override val sink: TaintVertex, - val rule: TaintMethodSink? = null, -) : Vulnerability diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt deleted file mode 100644 index 39e8e0aab..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.Vertex - -typealias TaintVertex = Vertex -typealias TaintEdge = Edge -typealias TaintRunner = Runner diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt deleted file mode 100644 index 261924328..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.sarif.VulnerabilityDescription -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.api.common.cfg.CommonInst - -fun UnusedVariableVulnerability.toSarif(): - VulnerabilityInstance = - VulnerabilityInstance( - TraceGraph(sink, mutableSetOf(sink), mutableMapOf(), emptyMap()), - VulnerabilityDescription(ruleId = null, message = message) - ) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt deleted file mode 100644 index 148e04b9c..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst - -context(Traits) -class UnusedVariableAnalyzer( - private val graph: ApplicationGraph, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: UnusedVariableFlowFunctions by lazy { - UnusedVariableFlowFunctions(graph) - } - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: Edge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) - } - } - - override fun handleCrossUnitCall( - caller: Vertex, - callee: Vertex, - ): List> { - return emptyList() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt deleted file mode 100644 index d4d323cd6..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Edge -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -sealed interface UnusedVariableEvent - where Method : CommonMethod, - Statement : CommonInst - -data class NewSummaryEdge( - val edge: Edge, -) : UnusedVariableEvent - where Method : CommonMethod, - Statement : CommonInst diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt deleted file mode 100644 index 894aaa75e..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.api.common.cfg.CommonInst - -sealed interface UnusedVariableDomainFact - -object UnusedVariableZeroFact : UnusedVariableDomainFact { - override fun toString(): String = "Zero" -} - -data class UnusedVariable( - val variable: AccessPath, - val initStatement: CommonInst, -) : UnusedVariableDomainFact diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt deleted file mode 100644 index 2f3d9aa08..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.FlowFunction -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.isOnHeap -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonProject -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcSpecialCallExpr -import org.jacodb.api.jvm.cfg.JcStaticCallExpr - -context(Traits) -class UnusedVariableFlowFunctions( - private val graph: ApplicationGraph, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection { - return setOf(UnusedVariableZeroFact) - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (current !is CommonAssignInst) { - return@FlowFunction setOf(fact) - } - - if (fact == UnusedVariableZeroFact) { - val toPath = current.lhv.toPath() - if (!toPath.isOnHeap) { - return@FlowFunction setOf(UnusedVariableZeroFact, UnusedVariable(toPath, current)) - } else { - return@FlowFunction setOf(UnusedVariableZeroFact) - } - } - check(fact is UnusedVariable) - - val toPath = current.lhv.toPath() - val default = if (toPath == fact.variable) emptySet() else setOf(fact) - val fromPath = current.rhv.toPathOrNull() - ?: return@FlowFunction default - - if (fromPath.isOnHeap || toPath.isOnHeap) { - return@FlowFunction default - } - - if (fromPath == fact.variable) { - return@FlowFunction default + fact.copy(variable = toPath) - } - - default - } - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - ) = obtainSequentFlowFunction(callStatement, returnSite) - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - if (fact == UnusedVariableZeroFact) { - // FIXME: use common? - if (callExpr !is JcStaticCallExpr && callExpr !is JcSpecialCallExpr) { - return@FlowFunction setOf(UnusedVariableZeroFact) - } - return@FlowFunction buildSet { - add(UnusedVariableZeroFact) - val callee = graph.methodOf(calleeStart) - val formalParams = getArgumentsOf(callee) - for (formal in formalParams) { - add(UnusedVariable(formal.toPath(), callStatement)) - } - } - } - check(fact is UnusedVariable) - - emptySet() - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - exitStatement: Statement, - ) = FlowFunction { fact -> - if (fact == UnusedVariableZeroFact) { - setOf(UnusedVariableZeroFact) - } else { - emptySet() - } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt deleted file mode 100644 index 687465415..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeoutOrNull -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.SummaryStorageImpl -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class UnusedVariableManager( - private val graph: ApplicationGraph, - private val unitResolver: UnitResolver, -) : Manager, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - private val methodsForUnit: MutableMap> = hashMapOf() - private val runnerForUnit: MutableMap> = hashMapOf() - private val queueIsEmpty = ConcurrentHashMap() - - private val summaryEdgesStorage = - SummaryStorageImpl>() - private val vulnerabilitiesStorage = - SummaryStorageImpl>() - - private val stopRendezvous = Channel(Channel.RENDEZVOUS) - - private fun newRunner( - unit: UnitType, - ): Runner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - logger.debug { "Creating a new runner for $unit" } - val analyzer = UnusedVariableAnalyzer(graph) - val runner = UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@UnusedVariableManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = UnusedVariableZeroFact - ) - - runnerForUnit[unit] = runner - return runner - } - - private fun getAllCallees(method: Method): Set { - val result: MutableSet = hashSetOf() - for (inst in method.flowGraph().instructions) { - @Suppress("UNCHECKED_CAST") - result += graph.callees(inst as Statement) - } - return result - } - - private fun addStart(method: Method) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - val isNew = methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - if (isNew) { - for (dep in getAllCallees(method)) { - addStart(dep) - } - } - } - - @JvmName("analyze") // needed for Java interop because of inline class (Duration) - @OptIn(ExperimentalTime::class) - fun analyze( - startMethods: List, - timeout: Duration = 3600.seconds, - ): List> = runBlocking { - val timeStart = TimeSource.Monotonic.markNow() - - // Add start methods: - for (method in startMethods) { - addStart(method) - } - - // Determine all units: - val allUnits = methodsForUnit.keys.toList() - logger.info { - "Starting analysis of ${ - methodsForUnit.values.sumOf { it.size } - } methods in ${allUnits.size} units" - } - - // Spawn runner jobs: - val allJobs = allUnits.map { unit -> - // Create the runner: - val runner = newRunner(unit) - - // Start the runner: - launch(start = CoroutineStart.LAZY) { - val methods = methodsForUnit[unit]!!.toList() - runner.run(methods) - } - } - - // Spawn progress job: - val progress = launch(Dispatchers.IO) { - while (isActive) { - delay(1.seconds) - logger.info { - "Progress: propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - } - } - - // Spawn stopper job: - val stopper = launch(Dispatchers.IO) { - stopRendezvous.receive() - logger.info { "Stopping all runners..." } - allJobs.forEach { it.cancel() } - } - - // Start all runner jobs: - val timeStartJobs = TimeSource.Monotonic.markNow() - allJobs.forEach { it.start() } - - // Await all runners: - withTimeoutOrNull(timeout) { - allJobs.joinAll() - } ?: run { - logger.info { "Timeout!" } - allJobs.forEach { it.cancel() } - allJobs.joinAll() - } - progress.cancelAndJoin() - stopper.cancelAndJoin() - logger.info { - "All ${allJobs.size} jobs completed in %.1f s".format( - timeStartJobs.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - - // Extract found vulnerabilities (sinks): - val foundVulnerabilities = allUnits.flatMap { unit -> - val runner = runnerForUnit[unit] ?: error("No runner for $unit") - val result = runner.getIfdsResult() - val allFacts = result.facts - - val used = hashMapOf() - for ((inst, facts) in allFacts) { - for (fact in facts) { - if (fact is UnusedVariable) { - @Suppress("UNCHECKED_CAST") - used.putIfAbsent(fact.initStatement as Statement, false) - if (fact.variable.isUsedAt(inst)) { - used[fact.initStatement] = true - } - } - } - } - used.filterValues { !it }.keys.map { - UnusedVariableVulnerability( - message = "Assigned value is unused", - sink = Vertex(it, UnusedVariableZeroFact) - ) - } - } - - if (logger.isDebugEnabled) { - logger.debug { "Total found ${foundVulnerabilities.size} vulnerabilities" } - for (vulnerability in foundVulnerabilities) { - logger.debug { "$vulnerability in ${vulnerability.method}" } - } - } - logger.info { "Total sinks: ${foundVulnerabilities.size}" } - logger.info { - "Total propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - logger.info { - "Analysis done in %.1f s".format( - timeStart.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - foundVulnerabilities - } - - override fun handleEvent(event: UnusedVariableEvent) { - when (event) { - is NewSummaryEdge -> { - summaryEdgesStorage.add(UnusedVariableSummaryEdge(event.edge)) - } - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - queueIsEmpty[event.runner.unit] = event.isEmpty - if (event.isEmpty) { - if (runnerForUnit.keys.all { queueIsEmpty[it] == true }) { - logger.debug { "All runners are empty" } - stopRendezvous.trySend(Unit).getOrNull() - } - } - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (Edge) -> Unit, - ) { - summaryEdgesStorage - .getFacts(method) - .onEach { handler(it.edge) } - .launchIn(scope) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt deleted file mode 100644 index 86cd575c8..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.SummaryEdge -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.api.common.cfg.CommonInst - -data class UnusedVariableSummaryEdge( - override val edge: Edge, -) : SummaryEdge - -data class UnusedVariableVulnerability( - override val message: String, - override val sink: Vertex, -) : Vulnerability diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt deleted file mode 100644 index 6935c349d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcArrayAccess -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcBranchingInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.cfg.JcSpecialCallExpr -import org.jacodb.api.jvm.cfg.JcTerminatingInst - -context(Traits) -internal fun AccessPath.isUsedAt( - expr: CommonExpr, -): Boolean { - return expr.getValues().any { it.toPathOrNull() == this } -} - -context(Traits) -internal fun AccessPath.isUsedAt( - inst: CommonInst, -): Boolean { - val callExpr = inst.getCallExpr() - - if (callExpr != null) { - // Don't count constructor calls as usages - if (callExpr is JcSpecialCallExpr - && callExpr.method.method.isConstructor - && isUsedAt(callExpr.instance) - ) { - return false - } - - return isUsedAt(callExpr) - } - if (inst is JcAssignInst) { - if (inst.lhv is JcArrayAccess && isUsedAt(inst.lhv)) { - return true - } - return isUsedAt(inst.rhv) && (inst.lhv !is JcLocal || inst.rhv !is JcLocal) - } - if (inst is JcTerminatingInst || inst is JcBranchingInst) { - inst as JcInst - return inst.operands.any { isUsedAt(it) } - } - return false -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt deleted file mode 100644 index eb11c3d10..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FieldAccessor -import org.jacodb.analysis.util.toPathOrNull -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonArgument -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.ets.base.EtsAnyType -import org.jacodb.ets.base.EtsArrayAccess -import org.jacodb.ets.base.EtsCallExpr -import org.jacodb.ets.base.EtsCastExpr -import org.jacodb.ets.base.EtsClassType -import org.jacodb.ets.base.EtsConstant -import org.jacodb.ets.base.EtsEntity -import org.jacodb.ets.base.EtsImmediate -import org.jacodb.ets.base.EtsInstanceFieldRef -import org.jacodb.ets.base.EtsParameterRef -import org.jacodb.ets.base.EtsStaticFieldRef -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.base.EtsThis -import org.jacodb.ets.base.EtsValue -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsMethodImpl -import org.jacodb.ets.model.EtsMethodParameter -import org.jacodb.ets.utils.callExpr -import org.jacodb.taint.configuration.ConstantValue -import org.jacodb.analysis.util.toPath as _toPath -import org.jacodb.analysis.util.toPathOrNull as _toPathOrNull -import org.jacodb.ets.utils.getOperands as _getOperands -import org.jacodb.ets.utils.getValues as _getValues - -interface EtsTraits : Traits { - - companion object : EtsTraits { - // Note: unused for now - // lateinit var cp: EtsFile - } - - override val CommonCallExpr.callee: EtsMethod - get() { - check(this is EtsCallExpr) - // TODO: here, we should use the classpath to resolve the method by its signature, like so: - // `return cp.getMethodBySignature(method) ?: error("Method not found: $method")` - // However, currently EtsFile (classpath) is not able to perform method lookup by signature, - // and even is not available in this context. - // So, we just construct a new method instance with necessary signature, but without a CFG, for now. - return EtsMethodImpl(method) - } - - override val EtsMethod.thisInstance: EtsThis - get() = EtsThis(EtsClassType(enclosingClass)) - - override val EtsMethod.isConstructor: Boolean - get() = name == "constructor" - - override fun CommonExpr.toPathOrNull(): AccessPath? { - check(this is EtsEntity) - return this._toPathOrNull() - } - - override fun CommonValue.toPathOrNull(): AccessPath? { - check(this is EtsValue) - return this._toPathOrNull() - } - - override fun CommonValue.toPath(): AccessPath { - check(this is EtsValue) - return this._toPath() - } - - override fun getArgument(param: CommonMethodParameter): EtsParameterRef { - check(param is EtsMethodParameter) - return EtsParameterRef(index = param.index, type = param.type) - } - - override fun getArgumentsOf(method: EtsMethod): List { - return method.parameters.map { getArgument(it) } - } - - override fun CommonValue.isConstant(): Boolean { - check(this is EtsEntity) - return this is org.jacodb.ets.base.EtsConstant - } - - override fun CommonValue.eqConstant(constant: ConstantValue): Boolean { - TODO("Not yet implemented") - } - - override fun CommonValue.ltConstant(constant: ConstantValue): Boolean { - TODO("Not yet implemented") - } - - override fun CommonValue.gtConstant(constant: ConstantValue): Boolean { - TODO("Not yet implemented") - } - - override fun CommonValue.matches(pattern: String): Boolean { - TODO("Not yet implemented") - } - - override fun EtsStmt.getCallExpr(): EtsCallExpr? { - return callExpr - } - - override fun CommonExpr.getValues(): Set { - check(this is EtsEntity) - return _getValues().toSet() - } - - override fun EtsStmt.getOperands(): List { - return _getOperands().toList() - } -} - -fun EtsEntity.toPathOrNull(): AccessPath? = when (this) { - is EtsImmediate -> AccessPath(this, emptyList()) - - is EtsThis -> AccessPath(this, emptyList()) - - is EtsParameterRef -> AccessPath(this, emptyList()) - - is EtsArrayAccess -> { - array.toPathOrNull()?.let { - it + ElementAccessor - } - } - - is EtsInstanceFieldRef -> { - instance.toPathOrNull()?.let { - it + FieldAccessor(field.name) - } - } - - is EtsStaticFieldRef -> { - AccessPath(null, listOf(FieldAccessor(field.name, isStatic = true))) - } - - is EtsCastExpr -> arg.toPathOrNull() - - else -> null -} - -fun EtsEntity.toPath(): AccessPath { - return toPathOrNull() ?: error("Unable to build access path for value $this") -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt deleted file mode 100644 index b6556ac2b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FieldAccessor -import org.jacodb.analysis.util.getArgument -import org.jacodb.analysis.util.toPathOrNull -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.JcParameter -import org.jacodb.api.jvm.cfg.JcArgument -import org.jacodb.api.jvm.cfg.JcArrayAccess -import org.jacodb.api.jvm.cfg.JcBool -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcCastExpr -import org.jacodb.api.jvm.cfg.JcConstant -import org.jacodb.api.jvm.cfg.JcExpr -import org.jacodb.api.jvm.cfg.JcFieldRef -import org.jacodb.api.jvm.cfg.JcImmediate -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInt -import org.jacodb.api.jvm.cfg.JcStringConstant -import org.jacodb.api.jvm.cfg.JcThis -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.api.jvm.cfg.values -import org.jacodb.api.jvm.ext.toType -import org.jacodb.taint.configuration.ConstantBooleanValue -import org.jacodb.taint.configuration.ConstantIntValue -import org.jacodb.taint.configuration.ConstantStringValue -import org.jacodb.taint.configuration.ConstantValue -import org.jacodb.analysis.util.callee as _callee -import org.jacodb.analysis.util.getArgument as _getArgument -import org.jacodb.analysis.util.getArgumentsOf as _getArgumentsOf -import org.jacodb.analysis.util.thisInstance as _thisInstance -import org.jacodb.analysis.util.toPath as _toPath -import org.jacodb.analysis.util.toPathOrNull as _toPathOrNull -import org.jacodb.api.jvm.ext.cfg.callExpr as _callExpr - -/** - * JVM-specific extensions for analysis. - * - * ### Usage: - * ``` - * class MyClass { - * companion object : JcTraits - * } - * ``` - */ -interface JcTraits : Traits { - - val cp: JcClasspath - get() = JcTraits.cp - - override val JcMethod.thisInstance: JcThis - get() = _thisInstance - - @Suppress("EXTENSION_SHADOWED_BY_MEMBER") - override val JcMethod.isConstructor: Boolean - get() = isConstructor - - override fun CommonExpr.toPathOrNull(): AccessPath? { - check(this is JcExpr) - return _toPathOrNull() - } - - override fun CommonValue.toPathOrNull(): AccessPath? { - check(this is JcValue) - return _toPathOrNull() - } - - override fun CommonValue.toPath(): AccessPath { - check(this is JcValue) - return _toPath() - } - - override val CommonCallExpr.callee: JcMethod - get() { - check(this is JcCallExpr) - return _callee - } - - override fun getArgument(param: CommonMethodParameter): JcArgument? { - check(param is JcParameter) - return cp._getArgument(param) - } - - override fun getArgumentsOf(method: JcMethod): List { - return cp._getArgumentsOf(method) - } - - override fun CommonValue.isConstant(): Boolean { - check(this is JcValue) - return this is JcConstant - } - - override fun CommonValue.eqConstant(constant: ConstantValue): Boolean { - check(this is JcValue) - return when (constant) { - is ConstantBooleanValue -> { - this is JcBool && value == constant.value - } - - is ConstantIntValue -> { - this is JcInt && value == constant.value - } - - is ConstantStringValue -> { - // TODO: if 'value' is not string, convert it to string and compare with 'constant.value' - this is JcStringConstant && value == constant.value - } - } - } - - override fun CommonValue.ltConstant(constant: ConstantValue): Boolean { - check(this is JcValue) - return when (constant) { - is ConstantIntValue -> { - this is JcInt && value < constant.value - } - - else -> error("Unexpected constant: $constant") - } - } - - override fun CommonValue.gtConstant(constant: ConstantValue): Boolean { - check(this is JcValue) - return when (constant) { - is ConstantIntValue -> { - this is JcInt && value > constant.value - } - - else -> error("Unexpected constant: $constant") - } - } - - override fun CommonValue.matches(pattern: String): Boolean { - check(this is JcValue) - val s = this.toString() - val re = pattern.toRegex() - return re.matches(s) - } - - override fun JcInst.getCallExpr(): CommonCallExpr? { - return _callExpr - } - - override fun CommonExpr.getValues(): Set { - check(this is JcExpr) - return values - } - - override fun JcInst.getOperands(): List { - return operands - } - - // Ensure that all methods are default-implemented in the interface itself: - companion object : JcTraits { - override lateinit var cp: JcClasspath - } -} - -val JcMethod.thisInstance: JcThis - get() = JcThis(enclosingClass.toType()) - -val JcCallExpr.callee: JcMethod - get() = method.method - -fun JcExpr.toPathOrNull(): AccessPath? = when (this) { - is JcValue -> toPathOrNull() - is JcCastExpr -> operand.toPathOrNull() - else -> null -} - -fun JcValue.toPathOrNull(): AccessPath? = when (this) { - is JcImmediate -> AccessPath(this, emptyList()) - - is JcArrayAccess -> { - array.toPathOrNull()?.let { - it + ElementAccessor - } - } - - is JcFieldRef -> { - val instance = instance - if (instance == null) { - require(field.isStatic) { "Expected static field" } - AccessPath(null, listOf(FieldAccessor(field.name, isStatic = true))) - } else { - instance.toPathOrNull()?.let { - it + FieldAccessor(field.name) - } - } - } - - else -> null -} - -fun JcValue.toPath(): AccessPath { - return toPathOrNull() ?: error("Unable to build access path for value $this") -} - -fun JcClasspath.getArgument(param: JcParameter): JcArgument? { - val t = findTypeOrNull(param.type.typeName) ?: return null - return JcArgument.of(param.index, param.name, t) -} - -fun JcClasspath.getArgumentsOf(method: JcMethod): List { - return method.parameters.map { getArgument(it)!! } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt deleted file mode 100644 index d1295acf2..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FieldAccessor -import org.jacodb.analysis.util.getArgument -import org.jacodb.analysis.util.toPathOrNull -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.panda.staticvm.cfg.PandaArgument -import org.jacodb.panda.staticvm.cfg.PandaArrayAccess -import org.jacodb.panda.staticvm.cfg.PandaCallExpr -import org.jacodb.panda.staticvm.cfg.PandaCastExpr -import org.jacodb.panda.staticvm.cfg.PandaConstant -import org.jacodb.panda.staticvm.cfg.PandaExpr -import org.jacodb.panda.staticvm.cfg.PandaFieldRef -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.cfg.PandaPhiExpr -import org.jacodb.panda.staticvm.cfg.PandaSimpleValue -import org.jacodb.panda.staticvm.cfg.PandaThis -import org.jacodb.panda.staticvm.cfg.PandaValue -import org.jacodb.panda.staticvm.classpath.PandaClass -import org.jacodb.panda.staticvm.classpath.PandaClassType -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.taint.configuration.ConstantBooleanValue -import org.jacodb.taint.configuration.ConstantIntValue -import org.jacodb.taint.configuration.ConstantStringValue -import org.jacodb.taint.configuration.ConstantValue -import org.jacodb.analysis.util.getArgument as _getArgument -import org.jacodb.analysis.util.getArgumentsOf as _getArgumentsOf -import org.jacodb.analysis.util.thisInstance as _thisInstance -import org.jacodb.analysis.util.toPath as _toPath -import org.jacodb.analysis.util.toPathOrNull as _toPathOrNull -import org.jacodb.analysis.util.toPaths as _toPaths -import org.jacodb.panda.staticvm.utils.callExpr as _callExpr - -/** - * Panda-specific extensions for analysis. - * - * ### Usage: - * ``` - * class MyClass { - * companion object : PandaTraits - * } - * ``` - */ -interface PandaStaticTraits : Traits { - - override val PandaMethod.thisInstance: PandaThis - get() = _thisInstance - - override val PandaMethod.isConstructor: Boolean - get() = name == "" - - override fun CommonExpr.toPathOrNull(): AccessPath? { - check(this is PandaExpr) - return _toPathOrNull() - } - - override fun CommonExpr.toPaths(): List { - check(this is PandaExpr) - return _toPaths() - } - - override fun CommonValue.toPathOrNull(): AccessPath? { - check(this is PandaValue) - return _toPathOrNull() - } - - override fun CommonValue.toPath(): AccessPath { - check(this is PandaValue) - return _toPath() - } - - override val CommonCallExpr.callee: PandaMethod - get() { - check(this is PandaCallExpr) - return method - } - - override fun PandaInst.getCallExpr(): CommonCallExpr? = _callExpr - - override fun getArgument(param: CommonMethodParameter): PandaArgument { - check(param is PandaMethod.Parameter) - return _getArgument(param) - } - - override fun getArgumentsOf(method: PandaMethod): List { - return _getArgumentsOf(method) - } - - override fun CommonValue.isConstant(): Boolean { - check(this is PandaValue) - return this is PandaConstant - } - - override fun CommonValue.eqConstant(constant: ConstantValue): Boolean { - check(this is PandaValue) - return when (constant) { - is ConstantBooleanValue -> { - // this is PandaBoolConstant && this.value == constant.value - TODO() - } - - is ConstantIntValue -> { - // this is PandaNumberConstant && this.value == constant.value - TODO() - } - - is ConstantStringValue -> { - // TODO: convert to string if necessary - // this is PandaStringConstant && this.value == constant.value - TODO() - } - } - } - - override fun CommonValue.ltConstant(constant: ConstantValue): Boolean { - check(this is PandaValue) - return when (constant) { - is ConstantIntValue -> { - // this is PandaNumberConstant && this.value < constant.value - TODO() - } - - else -> false - } - } - - override fun CommonValue.gtConstant(constant: ConstantValue): Boolean { - check(this is PandaValue) - return when (constant) { - is ConstantIntValue -> { - // this is PandaNumberConstant && this.value > constant.value - TODO() - } - - else -> false - } - } - - override fun CommonValue.matches(pattern: String): Boolean { - check(this is PandaValue) - val s = this.toString() - val re = pattern.toRegex() - return re.matches(s) - } - - override fun CommonExpr.getValues(): Set { - check(this is PandaExpr) - return TODO() - } - - override fun PandaInst.getOperands(): List { - return operands - } - - // Ensure that all methods are default-implemented in the interface itself: - companion object : PandaStaticTraits { - // Note: unused for now - // lateinit var cp: PandaProject - } -} - -val PandaMethod.thisInstance: PandaThis - get() = PandaThis("v0", enclosingClass.type) - -internal fun PandaClass.toType(): PandaClassType = type - -fun PandaExpr.toPathOrNull(): AccessPath? = when (this) { - is PandaValue -> toPathOrNull() - is PandaCastExpr -> arg.toPathOrNull() - else -> null -} - -fun PandaExpr.toPaths(): List = when (this) { - is PandaPhiExpr -> operands.mapNotNull(PandaValue::_toPathOrNull) - else -> listOfNotNull(_toPathOrNull()) -} - -fun PandaValue.toPathOrNull(): AccessPath? = when (this) { - is PandaSimpleValue -> AccessPath(this, emptyList()) - - is PandaArrayAccess -> { - array.toPathOrNull()?.let { - it + ElementAccessor - } - } - - is PandaFieldRef -> { - val instance = instance - if (instance == null) { - AccessPath(null, listOf(FieldAccessor(field.name, isStatic = true))) - } else { - instance.toPathOrNull()?.let { - it + FieldAccessor(field.name) - } - } - } - - else -> null -} - -fun PandaValue.toPath(): AccessPath { - return toPathOrNull() ?: error("Unable to build access path for value $this") -} - -fun getArgument(param: PandaMethod.Parameter): PandaArgument { - return PandaArgument(param.index, "arg${param.index}", param.type) -} - -fun getArgumentsOf(method: PandaMethod): List { - return method.parameters.map { getArgument(it) } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt deleted file mode 100644 index 6e47f32c9..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonArgument -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.taint.configuration.ConstantValue - -/** - * Extensions for analysis. - */ -interface Traits - where Method : CommonMethod, - Statement : CommonInst { - - val @UnsafeVariance Method.thisInstance: CommonThis - val @UnsafeVariance Method.isConstructor: Boolean - - fun CommonExpr.toPathOrNull(): AccessPath? - fun CommonValue.toPathOrNull(): AccessPath? - fun CommonValue.toPath(): AccessPath - - val CommonCallExpr.callee: Method - - fun getArgument(param: CommonMethodParameter): CommonArgument? - fun getArgumentsOf(method: @UnsafeVariance Method): List - - fun CommonValue.isConstant(): Boolean - fun CommonValue.eqConstant(constant: ConstantValue): Boolean - fun CommonValue.ltConstant(constant: ConstantValue): Boolean - fun CommonValue.gtConstant(constant: ConstantValue): Boolean - fun CommonValue.matches(pattern: String): Boolean - - // TODO: remove - fun CommonExpr.toPaths(): List = listOfNotNull(toPathOrNull()) - - fun @UnsafeVariance Statement.getCallExpr(): CommonCallExpr? - fun CommonExpr.getValues(): Set - fun @UnsafeVariance Statement.getOperands(): List -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt deleted file mode 100644 index aa6ae83f6..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.taint.TaintBidiRunner - -fun AccessPath?.startsWith(other: AccessPath?): Boolean { - if (this == null || other == null) { - return false - } - if (this.value != other.value) { - return false - } - return this.accesses.take(other.accesses.size) == other.accesses -} - -internal fun AccessPath.removeTrailingElementAccessors(): AccessPath { - var index = accesses.size - while (index > 0 && accesses[index - 1] is ElementAccessor) { - index-- - } - return AccessPath(value, accesses.subList(0, index)) -} - -fun Runner<*, *, *>.getPathEdges(): Set> = when (this) { - is UniRunner<*, *, *, *> -> pathEdges - is TaintBidiRunner<*, *> -> forwardRunner.getPathEdges() + backwardRunner.getPathEdges() - else -> error("Cannot extract pathEdges for $this") -} diff --git a/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java deleted file mode 100644 index 1bdda4a4b..000000000 --- a/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl; - -import kotlin.time.DurationUnit; -import org.jacodb.analysis.graph.ApplicationGraphFactory; -import org.jacodb.analysis.ifds.UnitResolver; -import org.jacodb.analysis.ifds.UnitResolverKt; -import org.jacodb.analysis.taint.TaintManager; -import org.jacodb.analysis.util.JcTraits; -import org.jacodb.api.jvm.JcClassOrInterface; -import org.jacodb.api.jvm.JcClasspath; -import org.jacodb.api.jvm.JcDatabase; -import org.jacodb.api.jvm.JcMethod; -import org.jacodb.api.jvm.analysis.JcApplicationGraph; -import org.jacodb.api.jvm.cfg.JcInst; -import org.jacodb.impl.JacoDB; -import org.jacodb.impl.JcSettings; -import org.jacodb.impl.features.InMemoryHierarchy; -import org.jacodb.impl.features.Usages; -import org.jacodb.testing.LibrariesMixinKt; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import static kotlin.time.DurationKt.toDuration; - - -public class JavaAnalysisApiTest { - private static JcClasspath classpath; - - @BeforeAll - public static void initClasspath() throws ExecutionException, InterruptedException { - JcDatabase instance = JacoDB.async(new JcSettings().installFeatures(Usages.INSTANCE, InMemoryHierarchy.INSTANCE)).get(); - classpath = instance.asyncClasspath(LibrariesMixinKt.getAllClasspath()).get(); - } - - @Test - public void testJavaAnalysisApi() throws ExecutionException, InterruptedException { - JcClassOrInterface analyzedClass = classpath.findClassOrNull("org.jacodb.testing.analysis.NpeExamples"); - Assertions.assertNotNull(analyzedClass); - - List methodsToAnalyze = analyzedClass.getDeclaredMethods(); - JcApplicationGraph applicationGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, null) - .get(); - UnitResolver unitResolver = UnitResolverKt.getMethodUnitResolver(); - TaintManager manager = new TaintManager(JcTraits.Companion, applicationGraph, unitResolver, false, null); - manager.analyze(methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)); - } - - @Test - public void testCustomBannedPackagesApi() throws ExecutionException, InterruptedException { - List bannedPackages = new ArrayList<>(ApplicationGraphFactory.getDefaultBannedPackagePrefixes()); - bannedPackages.add("my.package.that.wont.be.analyzed"); - - JcApplicationGraph customGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, bannedPackages) - .get(); - Assertions.assertNotNull(customGraph); - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt deleted file mode 100644 index 3be16d2e9..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import juliet.support.AbstractTestCase -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.impl.features.classpaths.UnknownClasses -import org.jacodb.impl.features.hierarchyExt -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.testing.BaseTest -import org.jacodb.testing.WithGlobalDB -import org.jacodb.testing.allClasspath -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.params.provider.Arguments -import java.util.stream.Stream -import kotlin.streams.asStream - -private val logger = mu.KotlinLogging.logger {} - -abstract class BaseAnalysisTest : BaseTest() { - - companion object : WithGlobalDB(UnknownClasses), JcTraits { - - fun getJulietClasses( - cweNum: Int, - cweSpecificBans: List = emptyList(), - ): Sequence = runBlocking { - val cp = db.classpath(allClasspath) - val hierarchyExt = cp.hierarchyExt() - val baseClass = cp.findClass() - hierarchyExt.findSubClasses(baseClass, false) - .map { it.name } - .filter { it.contains("CWE${cweNum}_") } - .filterNot { className -> (commonJulietBans + cweSpecificBans).any { className.contains(it) } } - .sorted() - } - - @JvmStatic - fun provideClassesForJuliet( - cweNum: Int, - cweSpecificBans: List = emptyList(), - ): Stream = - getJulietClasses(cweNum, cweSpecificBans) - .map { Arguments.of(it) } - .asStream() - - private val commonJulietBans = listOf( - // TODO: containers not supported - "_72", "_73", "_74", - - // TODO/Won't fix(?): dead parts of switches shouldn't be analyzed - "_15", - - // TODO/Won't fix(?): passing through channels not supported - "_75", - - // TODO/Won't fix(?): constant private/static methods not analyzed - "_11", "_08", - - // TODO/Won't fix(?): unmodified non-final private variables not analyzed - "_05", "_07", - - // TODO/Won't fix(?): unmodified non-final static variables not analyzed - "_10", "_14", - ) - } - - override val cp: JcClasspath = runBlocking { - val configFileName = "config_small.json" - val configResource = this.javaClass.getResourceAsStream("/$configFileName") - if (configResource != null) { - val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - protected val graph: JcApplicationGraph by lazy { - runBlocking { - cp.newApplicationGraphForAnalysis() - } - } - - protected fun testSingleJulietClass( - className: String, - findSinks: (JcMethod) -> List>, - ) { - logger.info { className } - - val clazz = cp.findClass(className) - val badMethod = clazz.methods.single { it.name == "bad" } - val goodMethod = clazz.methods.single { it.name == "good" } - - logger.info { "Searching for sinks in BAD method: $badMethod" } - val badIssues = findSinks(badMethod) - logger.info { "Total ${badIssues.size} issues in BAD method" } - for (issue in badIssues) { - logger.debug { " - $issue" } - } - assertTrue(badIssues.isNotEmpty()) { "Must find some sinks in 'bad' for $className" } - - logger.info { "Searching for sinks in GOOD method: $goodMethod" } - val goodIssues = findSinks(goodMethod) - logger.info { "Total ${goodIssues.size} issues in GOOD method" } - for (issue in goodIssues) { - logger.debug { " - $issue" } - } - assertTrue(goodIssues.isEmpty()) { "Must NOT find any sinks in 'good' for $className" } - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt deleted file mode 100644 index c99bb98e8..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import io.mockk.every -import io.mockk.mockk -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.toMaybe -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcPrimitiveType -import org.jacodb.api.jvm.JcType -import org.jacodb.api.jvm.PredefinedPrimitive -import org.jacodb.api.jvm.PredefinedPrimitives -import org.jacodb.api.jvm.cfg.JcBool -import org.jacodb.api.jvm.cfg.JcInt -import org.jacodb.api.jvm.cfg.JcStringConstant -import org.jacodb.api.jvm.cfg.JcThis -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.taint.configuration.And -import org.jacodb.taint.configuration.AnnotationType -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.ConditionVisitor -import org.jacodb.taint.configuration.ConstantBooleanValue -import org.jacodb.taint.configuration.ConstantEq -import org.jacodb.taint.configuration.ConstantGt -import org.jacodb.taint.configuration.ConstantIntValue -import org.jacodb.taint.configuration.ConstantLt -import org.jacodb.taint.configuration.ConstantMatches -import org.jacodb.taint.configuration.ConstantStringValue -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.IsConstant -import org.jacodb.taint.configuration.IsType -import org.jacodb.taint.configuration.Not -import org.jacodb.taint.configuration.Or -import org.jacodb.taint.configuration.Position -import org.jacodb.taint.configuration.SourceFunctionMatches -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.This -import org.jacodb.taint.configuration.TypeMatches -import org.junit.jupiter.api.Test -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class ConditionEvaluatorTest { - - companion object : JcTraits - - private val cp = mockk() - - private val intType: JcPrimitiveType = PredefinedPrimitive(cp, PredefinedPrimitives.Int) - private val boolType: JcPrimitiveType = PredefinedPrimitive(cp, PredefinedPrimitives.Boolean) - private val stringType = mockk { - every { classpath } returns cp - } - - private val intArg: Position = Argument(0) - private val intValue = JcInt(42, intType) - - private val boolArg: Position = Argument(1) - private val boolValue = JcBool(true, boolType) - - private val stringArg: Position = Argument(2) - private val stringValue = JcStringConstant("test", stringType) - - private val thisPos: Position = This - private val thisValue = JcThis(type = mockk()) - - private val positionResolver: (position: Position) -> Maybe = { position -> - when (position) { - intArg -> intValue - boolArg -> boolValue - stringArg -> stringValue - thisPos -> thisValue - else -> null - }.toMaybe() - } - private val evaluator: ConditionVisitor = BasicConditionEvaluator(positionResolver) - - @Test - fun `True is true`() { - val condition = ConstantTrue - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `Not(True) is false`() { - val condition = Not(ConstantTrue) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `Not(Not(True)) is true`() { - val condition = Not(Not(ConstantTrue)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `And(True) is true`() { - val condition = And(listOf(ConstantTrue, ConstantTrue, ConstantTrue)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `And(Not(True)) is false`() { - val condition = And(listOf(ConstantTrue, ConstantTrue, Not(ConstantTrue))) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `Or(Not(True)) is false`() { - val condition = Or(listOf(Not(ConstantTrue), Not(ConstantTrue), Not(ConstantTrue))) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `Or(True) is true`() { - val condition = Or(listOf(Not(ConstantTrue), Not(ConstantTrue), ConstantTrue)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(int) is true`() { - val condition = IsConstant(intArg) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(bool) is true`() { - val condition = IsConstant(boolArg) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(this) is false`() { - val condition = IsConstant(thisPos) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(unresolved) is false`() { - val condition = IsConstant(position = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `IsType in unexpected`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `AnnotationType in unexpected`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `ConstantEq(intArg(42), 42) is true`() { - val condition = ConstantEq(intArg, ConstantIntValue(42)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(intArg(42), 999) is false`() { - val condition = ConstantEq(intArg, ConstantIntValue(999)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(boolArg(true), true) is true`() { - val condition = ConstantEq(boolArg, ConstantBooleanValue(true)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(boolArg(true), false) is false`() { - val condition = ConstantEq(boolArg, ConstantBooleanValue(false)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(stringArg('test'), 'test') is true`() { - val condition = ConstantEq(stringArg, ConstantStringValue("test")) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(stringArg('test'), 'other') is false`() { - val condition = ConstantEq(stringArg, ConstantStringValue("other")) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(unresolved, any) is false`() { - val condition = ConstantEq(position = mockk(), value = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantLt(intArg(42), 999) is true`() { - val condition = ConstantLt(intArg, ConstantIntValue(999)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantLt(intArg(42), 5) is false`() { - val condition = ConstantLt(intArg, ConstantIntValue(5)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantLt(unresolved, any) is false`() { - val condition = ConstantLt(position = mockk(), value = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantGt(intArg(42), 5) is true`() { - val condition = ConstantGt(intArg, ConstantIntValue(5)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantGt(intArg(42), 999) is false`() { - val condition = ConstantGt(intArg, ConstantIntValue(999)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantGt(unresolved, any) is false`() { - val condition = ConstantGt(position = mockk(), value = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(intArg(42), '42') is true`() { - val condition = ConstantMatches(intArg, "42") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(intArg(42), 'd+') is true`() { - val condition = ConstantMatches(intArg, "\\d+") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(stringArg('test'), 'test') is true`() { - val condition = ConstantMatches(stringArg, "\"test\"") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(stringArg('test'), 'w+') is true`() { - val condition = ConstantMatches(stringArg, "\"\\w+\"") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(unresolved, any) is false`() { - val condition = ConstantMatches(position = mockk(), pattern = ".*") - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `SourceFunctionMatches is not implemented yet`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `ContainsMark is not supported by basic evaluator`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `TypeMatches(intArg, Int) is true`() { - val condition = TypeMatches(intArg, intType) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `TypeMatches(boolArg, Boolean) is true`() { - val condition = TypeMatches(boolArg, boolType) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `TypeMatches(stringArg, String) is true`() { - val condition = TypeMatches(stringArg, stringType) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `TypeMatches(unresolved, any) is false`() { - val condition = TypeMatches(position = mockk(), type = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `FactAwareConditionEvaluator supports ContainsMark`() { - val fact = Tainted(intValue.toPath(), TaintMark("FOO")) - val factAwareEvaluator = FactAwareConditionEvaluator(fact, positionResolver) - assertTrue(factAwareEvaluator.visit(ContainsMark(intArg, TaintMark("FOO")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(intArg, TaintMark("BAR")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(stringArg, TaintMark("FOO")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(stringArg, TaintMark("BAR")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(position = mockk(), TaintMark("FOO")))) - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt deleted file mode 100644 index cbb3cb0a0..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.constructors -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.impl.features.usagesExt -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.jacodb.testing.analysis.NpeExamples -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.StringTokenizer -import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -abstract class IfdsNpeTest : BaseAnalysisTest() { - - companion object { - @JvmStatic - fun provideClassesForJuliet476(): Stream = - provideClassesForJuliet(476, listOf("null_check_after_deref")) - - @JvmStatic - fun provideClassesForJuliet690(): Stream = - provideClassesForJuliet(690) - } - - @Test - fun `fields resolving should work through interfaces`() = runBlocking { - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val callers = graph.callers(cp.findClass().constructors[2]) - logger.debug { "callers: ${callers.toList().size}" } - } - - @Test - fun `analyze simple NPE`() { - testOneMethod("npeOnLength", listOf("%3 = x.length()")) - } - - @Test - fun `analyze no NPE`() { - testOneMethod("noNPE", emptyList()) - } - - @Test - fun `analyze NPE after fun with two exits`() { - testOneMethod( - "npeAfterTwoExits", - listOf("%4 = x.length()", "%5 = y.length()") - ) - } - - @Test - fun `no NPE after checked access`() { - testOneMethod("checkedAccess", emptyList()) - } - - @Disabled("Aliasing") - @Test - fun `no NPE after checked access with field`() { - testOneMethod("checkedAccessWithField", emptyList()) - } - - @Test - fun `consecutive NPEs handled properly`() { - testOneMethod( - "consecutiveNPEs", - listOf("a = x.length()", "c = x.length()") - ) - } - - @Test - fun `npe on virtual call when possible`() { - testOneMethod( - "possibleNPEOnVirtualCall", - listOf("%0 = x.length()") - ) - } - - @Test - fun `no npe on virtual call when impossible`() { - testOneMethod( - "noNPEOnVirtualCall", - emptyList() - ) - } - - @Test - fun `basic test for NPE on fields`() { - testOneMethod("simpleNPEOnField", listOf("len2 = second.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `simple points-to analysis`() { - testOneMethod("simplePoints2", listOf("%5 = %4.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `complex aliasing`() { - testOneMethod("complexAliasing", listOf("%6 = %5.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `context injection in points-to`() { - testOneMethod( - "contextInjection", - listOf("%6 = %5.length()", "%3 = %2.length()") - ) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `activation points maintain flow sensitivity`() { - testOneMethod("flowSensitive", listOf("%8 = %7.length()")) - } - - @Test - fun `overridden null assignment in callee don't affect next caller's instructions`() { - testOneMethod("overriddenNullInCallee", emptyList()) - } - - @Test - fun `recursive classes handled correctly`() { - testOneMethod( - "recursiveClass", - listOf("%10 = %9.toString()", "%15 = %14.toString()") - ) - } - - @Test - fun `NPE on uninitialized array element dereferencing`() { - testOneMethod("simpleArrayNPE", listOf("b = %4.length()")) - } - - @Test - fun `no NPE on array element dereferencing after initialization`() { - testOneMethod("noNPEAfterArrayInit", emptyList()) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `array aliasing`() { - testOneMethod("arrayAliasing", listOf("%5 = %4.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `mixed array and class aliasing`() { - testOneMethod("mixedArrayClassAliasing", listOf("%13 = %12.length()")) - } - - @Test - fun `dereferencing field of null object`() { - testOneMethod("npeOnFieldDeref", listOf("s = a.field")) - } - - @Test - fun `dereferencing copy of value saved before null assignment produce no npe`() { - testOneMethod("copyBeforeNullAssignment", emptyList()) - } - - @Test - fun `assigning null to copy doesn't affect original value`() { - testOneMethod("nullAssignmentToCopy", emptyList()) - } - - private fun findSinks(method: JcMethod): List> { - val unitResolver = SingletonUnitResolver - val manager = NpeManager(graph, unitResolver) - return manager.analyze(listOf(method), timeout = 30.seconds) - } - - @ParameterizedTest - @MethodSource("provideClassesForJuliet476") - fun `test on Juliet's CWE 476`(className: String) { - testSingleJulietClass(className, ::findSinks) - } - - @ParameterizedTest - @MethodSource("provideClassesForJuliet690") - fun `test on Juliet's CWE 690`(className: String) { - testSingleJulietClass(className, ::findSinks) - } - - @Test - fun `test on specific Juliet's testcase`() { - // val className = "juliet.testcases.CWE476_NULL_Pointer_Dereference.CWE476_NULL_Pointer_Dereference__Integer_01" - // val className = "juliet.testcases.CWE690_NULL_Deref_From_Return.CWE690_NULL_Deref_From_Return__Class_StringBuilder_01" - val className = - "juliet.testcases.CWE690_NULL_Deref_From_Return.CWE690_NULL_Deref_From_Return__Properties_getProperty_equals_01" - - testSingleJulietClass(className, ::findSinks) - } - - private inline fun testOneMethod( - methodName: String, - expectedLocations: Collection, - ) { - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val sinks = findSinks(method) - - // TODO: think about better assertions here - Assertions.assertEquals(expectedLocations.size, sinks.size) - expectedLocations.forEach { expected -> - Assertions.assertTrue(sinks.map { it.sink.toString() }.any { it.contains(expected) }) - } - } -} - -class IfdsNpeSqlTest : IfdsNpeTest() { - companion object : WithDB(Usages, InMemoryHierarchy) -} - -class IfdsNpeRAMTest : IfdsNpeTest() { - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} \ No newline at end of file diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt deleted file mode 100644 index 7128b4ba8..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.jacodb.analysis.ifds.ClassUnitResolver -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.toSarif -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.jacodb.testing.analysis.SqlInjectionExamples -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -abstract class IfdsSqlTest : BaseAnalysisTest() { - - companion object { - @JvmStatic - fun provideClassesForJuliet89(): Stream = provideClassesForJuliet(89, specificBansCwe89) - - private val specificBansCwe89: List = listOf( - // Not working yet (#156) - "s03", "s04" - ) - } - - private val myJson = Json { - prettyPrint = true - } - - @Test - fun `simple SQL injection`() { - val methodName = "bad" - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val methods = listOf(method) - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 30.seconds) - assertTrue(sinks.isNotEmpty()) - val sink = sinks.first() - val graph = manager.vulnerabilityTraceGraph(sink) - val trace = graph.getAllTraces().first() - assertTrue(trace.isNotEmpty()) - } - - @ParameterizedTest - @MethodSource("provideClassesForJuliet89") - fun `test on Juliet's CWE 89`(className: String) { - testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) - } - } - - @Test - fun `test on specific Juliet instance`() { - val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__connect_tcp_execute_01" - testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) - } - } - - @Test - fun `test bidirectional runner and other stuff`() { - val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__Environment_executeBatch_51a" - val clazz = cp.findClass(className) - val badMethod = clazz.methods.single { it.name == "bad" } - val unitResolver = ClassUnitResolver(true) - val manager = TaintManager(graph, unitResolver, useBidiRunner = true) - val sinks = manager.analyze(listOf(badMethod), timeout = 30.seconds) - assertTrue(sinks.isNotEmpty()) - val sink = sinks.first() - val graph = manager.vulnerabilityTraceGraph(sink) - val trace = graph.getAllTraces().first() - assertTrue(trace.isNotEmpty()) - val sarif = sarifReportFromVulnerabilities(listOf(sink.toSarif(graph))) - val sarifJson = myJson.encodeToString(sarif) - logger.info { "SARIF:\n$sarifJson" } - } -} - -class IfdsSqlSqlTest : IfdsSqlTest() { - companion object : WithDB(Usages, InMemoryHierarchy) -} - -class IfdsSqlRAMTest : IfdsSqlTest() { - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt deleted file mode 100644 index 4531d690a..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.testing.analysis.TaintExamples -import org.junit.jupiter.api.Test -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class IfdsTaintTest : BaseAnalysisTest() { - - @Test - fun `analyze simple taint on bad method`() { - testOneMethod("bad") - } - - private fun findSinks(method: JcMethod): List> { - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - return manager.analyze(listOf(method), timeout = 3000.seconds) - } - - private inline fun testOneMethod(methodName: String) { - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val sinks = findSinks(method) - logger.info { "Sinks: ${sinks.size}" } - for ((i, sink) in sinks.withIndex()) { - logger.info { "[${i + 1}/${sinks.size}]: ${sink.sink}" } - } - assertTrue(sinks.isNotEmpty()) - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt deleted file mode 100644 index 2c23c22e4..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import kotlinx.coroutines.runBlocking -import mu.KotlinLogging -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.taint.TaintAnalysisOptions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.testing.WithDB -import org.jacodb.testing.allClasspath -import org.jacodb.testing.analysis.UntrustedLoopBound -import org.junit.jupiter.api.Test -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -private val logger = KotlinLogging.logger {} - -class Ifds2UpperBoundTest : BaseAnalysisTest() { - - companion object : WithDB(Usages, InMemoryHierarchy) - - override val cp: JcClasspath = runBlocking { - val defaultConfigResource = this.javaClass.getResourceAsStream("/config_untrusted_loop_bound.json") - if (defaultConfigResource != null) { - val configJson = defaultConfigResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - @Test - fun `analyze untrusted upper bound`() { - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - testOneMethod("handle") - } - - private inline fun testOneMethod(methodName: String) { - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(listOf(method), timeout = 60.seconds) - logger.info { "Sinks: ${sinks.size}" } - for (sink in sinks) { - logger.info { sink } - } - assertTrue(sinks.isNotEmpty()) - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt deleted file mode 100644 index ca17c3a28..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds - -abstract class IfdsUnusedTest : BaseAnalysisTest() { - - companion object { - @JvmStatic - fun provideClassesForJuliet563(): Stream = provideClassesForJuliet( - 563, listOf( - // Unused variables are already optimized out by cfg - "unused_uninit_variable_", - "unused_init_variable_int", - "unused_init_variable_long", - "unused_init_variable_String_", - - // Unused variable is generated by cfg (!!) - "unused_value_StringBuilder_17", - - // Expected answers are strange, seems to be problem in tests - "_12", - - // The variable isn't expected to be detected as unused actually - "_81" - ) - ) - } - - @Disabled("#220") - @ParameterizedTest - @MethodSource("provideClassesForJuliet563") - fun `test on Juliet's CWE 563`(className: String) { - testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) - } - } - - @Test - fun `test on specific Juliet instance`() { - val className = - "juliet.testcases.CWE563_Unused_Variable.CWE563_Unused_Variable__unused_init_variable_StringBuilder_01" - val clazz = cp.findClass(className) - val badMethod = clazz.methods.single { it.name == "bad" } - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - val sinks = manager.analyze(listOf(badMethod), timeout = 30.seconds) - Assertions.assertTrue(sinks.isNotEmpty()) - } -} - - -class IfdsUnusedSqlTest : IfdsUnusedTest() { - - companion object : WithDB(Usages, InMemoryHierarchy) -} - -class IfdsUnusedRAMTest : IfdsUnusedTest() { - - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt deleted file mode 100644 index a5a1f50af..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.testing.WithGlobalDB -import org.jacodb.testing.allClasspath -import org.joda.time.DateTime -import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class JodaDateTimeAnalysisTest : BaseAnalysisTest() { - - companion object : WithGlobalDB() - - override val cp: JcClasspath = runBlocking { - val configFileName = "config_small.json" - val configResource = this.javaClass.getResourceAsStream("/$configFileName") - if (configResource != null) { - val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - @Test - fun `test taint analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Vulnerabilities found: ${sinks.size}" } - } - - @Test - fun `test NPE analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = NpeManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Vulnerabilities found: ${sinks.size}" } - } - - @Test - fun `test unused variables analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Unused variables found: ${sinks.size}" } - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt deleted file mode 100644 index d854b2585..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import org.jacodb.analysis.impl.custom.NullAssumptionAnalysis -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.testing.BaseTest -import org.jacodb.testing.WithGlobalDB -import org.jacodb.testing.cfg.NullAssumptionAnalysisExample -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test - -class NullabilityAssumptionAnalysisTest : BaseTest() { - - companion object : WithGlobalDB() - - @Test - fun `null-assumption analysis should work`() { - val clazz = cp.findClass() - with(clazz.findMethod("test1").flowGraph()) { - val analysis = NullAssumptionAnalysis(this).also { - it.run() - } - val sout = (instructions[0] as JcAssignInst).lhv as JcLocal - val a = ((instructions[3] as JcAssignInst).rhv as JcInstanceCallExpr).instance - - assertTrue(analysis.isAssumedNonNullBefore(instructions[2], a)) - assertTrue(analysis.isAssumedNonNullBefore(instructions[0], sout)) - } - } - - @Test - fun `null-assumption analysis should work 2`() { - val clazz = cp.findClass() - with(clazz.findMethod("test2").flowGraph()) { - val analysis = NullAssumptionAnalysis(this).also { - it.run() - } - val sout = (instructions[0] as JcAssignInst).lhv as JcLocal - val a = ((instructions[3] as JcAssignInst).rhv as JcInstanceCallExpr).instance - val x = (instructions[5] as JcAssignInst).lhv as JcLocal - - assertTrue(analysis.isAssumedNonNullBefore(instructions[2], a)) - assertTrue(analysis.isAssumedNonNullBefore(instructions[0], sout)) - analysis.isAssumedNonNullBefore(instructions[5], x) - } - } - - private fun JcClassOrInterface.findMethod(name: String): JcMethod = declaredMethods.first { it.name == name } - -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt deleted file mode 100644 index f890d8e9f..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.analysis.impl - -import io.mockk.every -import io.mockk.mockk -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClassType -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcArgument -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcCallInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.cfg.JcLocalVar -import org.jacodb.api.jvm.cfg.JcReturnInst -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.findTypeOrNull -import org.jacodb.api.jvm.ext.packageName -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.testing.BaseTest -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.jacodb.testing.allClasspath -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -open class TaintFlowFunctionsTest : BaseTest() { - - companion object : WithDB(Usages, InMemoryHierarchy), JcTraits - - override val cp: JcClasspath = runBlocking { - val configFileName = "config_test.json" - val configResource = this.javaClass.getResourceAsStream("/$configFileName") - if (configResource != null) { - val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - private val graph: JcApplicationGraph = mockk { - every { cp } returns this@TaintFlowFunctionsTest.cp - every { callees(any()) } answers { - sequenceOf(arg(0).callExpr!!.callee) - } - every { methodOf(any()) } answers { - arg(0).location.method - } - } - - private val stringType = cp.findTypeOrNull() as JcClassType - - private val testMethod = mockk { - every { name } returns "test" - every { enclosingClass } returns mockk(relaxed = true) { - every { packageName } returns "com.example" - every { simpleName } returns "Example" - every { name } returns "com.example.Example" - every { superClass } returns null - every { interfaces } returns emptyList() - } - every { isConstructor } returns false - every { returnType } returns mockk(relaxed = true) - every { parameters } returns listOf( - mockk(relaxed = true) { - every { index } returns 0 - every { type } returns mockk { - every { typeName } returns "java.lang.String" - } - } - ) - } - - @Test - fun `test obtain start facts`() { - val flowSpace = ForwardTaintFlowFunctions(graph) - val facts = flowSpace.obtainPossibleStartFacts(testMethod).toList() - val arg0 = getArgument(testMethod.parameters[0])!! - val arg0Taint = Tainted(arg0.toPath(), TaintMark("EXAMPLE")) - Assertions.assertEquals(listOf(TaintZeroFact, arg0Taint), facts) - } - - @Test - fun `test sequential flow function assign mark`() { - // "x := y", where 'y' is tainted, should result in both 'x' and 'y' to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val y: JcLocal = JcLocalVar(2, "y", stringType) - val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainSequentFlowFunction(inst, next = mockk()) - val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) - val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = f.compute(yTaint).toList() - Assertions.assertEquals(listOf(yTaint, xTaint), facts) - } - - @Test - fun `test call flow function assign mark`() { - // "x := test(...)", where 'test' is a source, should result in 'x' to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcAssignInst(location = mockk(), lhv = x, rhv = mockk { - every { method.method } returns testMethod - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) - val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) - val facts = f.compute(TaintZeroFact).toList() - Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) - } - - @Test - fun `test call flow function remove mark`() { - // "test(x)", where 'x' is tainted, should result in 'x' NOT to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcCallInst(location = mockk(), callExpr = mockk { - every { method.method } returns testMethod - every { args } returns listOf(x) - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) - val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) - val facts = f.compute(xTaint).toList() - Assertions.assertTrue(facts.isEmpty()) - } - - @Test - fun `test call flow function copy mark`() { - // "y := test(x)" should result in 'y' to be tainted only when 'x' is tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val y: JcLocal = JcLocalVar(2, "y", stringType) - val callStatement = JcAssignInst(location = mockk(), lhv = y, rhv = mockk { - every { method.method } returns testMethod - every { args } returns listOf(x) - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) - val xTaint = Tainted(x.toPath(), TaintMark("COPY")) - val yTaint = Tainted(y.toPath(), TaintMark("COPY")) - val facts = f.compute(xTaint).toList() - Assertions.assertEquals(listOf(xTaint, yTaint), facts) // copy from x to y - val other: JcLocal = JcLocalVar(10, "other", stringType) - val otherTaint = Tainted(other.toPath(), TaintMark("OTHER")) - val facts2 = f.compute(otherTaint).toList() - Assertions.assertEquals(listOf(otherTaint), facts2) // pass-through - } - - @Test - fun `test call to start flow function`() { - // "test(x)", where 'x' is tainted, should result in 'x' (formal argument of 'test') to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcCallInst(location = mockk(), callExpr = mockk { - every { method.method } returns testMethod - every { args } returns listOf(x) - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToStartFlowFunction(callStatement, calleeStart = mockk { - every { location } returns mockk { - every { method } returns testMethod - } - }) - val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val arg0: JcArgument = getArgument(testMethod.parameters[0])!! - val arg0Taint = Tainted(arg0.toPath(), TaintMark("TAINT")) - val facts = f.compute(xTaint).toList() - Assertions.assertEquals(listOf(arg0Taint), facts) - val other: JcLocal = JcLocalVar(10, "other", stringType) - val otherTaint = Tainted(other.toPath(), TaintMark("TAINT")) - val facts2 = f.compute(otherTaint).toList() - Assertions.assertTrue(facts2.isEmpty()) - } - - @Test - fun `test exit flow function`() { - // "x := test()" + "return y", where 'y' is tainted, should result in 'x' to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcAssignInst(location = mockk(), lhv = x, rhv = mockk { - every { method.method } returns testMethod - }) - val y: JcLocal = JcLocalVar(1, "y", stringType) - val exitStatement = JcReturnInst(location = mockk { - every { method } returns testMethod - }, returnValue = y) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainExitToReturnSiteFlowFunction(callStatement, returnSite = mockk(), exitStatement) - val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) - val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = f.compute(yTaint).toList() - Assertions.assertEquals(listOf(xTaint), facts) - } -} - -class TaintFlowFunctionsRAMTest : TaintFlowFunctionsTest() { - - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} diff --git a/jacodb-analysis/src/test/resources/additional.json b/jacodb-analysis/src/test/resources/additional.json deleted file mode 100644 index 4c883436e..000000000 --- a/jacodb-analysis/src/test/resources/additional.json +++ /dev/null @@ -1,607 +0,0 @@ -[ - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": ".*" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "AnnotationType", - "position": { - "_": "Argument", - "number": 0 - }, - "type": { - "_": "ClassMatcher", - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.springframework.web.bind.annotation" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "RequestParam" - } - } - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "XSS" - } - } - ] - }, - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": ".*" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "AnnotationType", - "position": { - "_": "Argument", - "number": 1 - }, - "type": { - "_": "ClassMatcher", - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.springframework.web.bind.annotation" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "RequestParam" - } - } - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 1 - }, - "mark": { - "name": "XSS" - } - } - ] - }, - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": ".*" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "AnnotationType", - "position": { - "_": "Argument", - "number": 2 - }, - "type": { - "_": "ClassMatcher", - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.springframework.web.bind.annotation" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "RequestParam" - } - } - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 2 - }, - "mark": { - "name": "XSS" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.net" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "URLDecoder" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "decode" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Connection" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "prepareCall|prepareStatement" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "PreparedStatement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "execute|executeQuery|executeUpdate|executeLargeUpdate" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "NETWORK" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ARGS" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "LDAP" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "FORM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "WEBSERVICE" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "PROPERTY" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ENVIRONMENT" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ICC" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "STREAM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "FILE_SYSTEM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "JSON" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "STDIN" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "DATABASE" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "CHANNEL" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "WEB" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "CONSOLE" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "XML" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "XSS" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "GUI_FORM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "NAMING" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "REGISTRY" - } - } - ] - } - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.util" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Map" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "get" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.util" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Map" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "put|replace" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 1 - }, - "to": { - "_": "This" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Base64" - }, - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.apache.commons.codec.binary" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "decodeBase64" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - } -] diff --git a/jacodb-analysis/src/test/resources/config_small.json b/jacodb-analysis/src/test/resources/config_small.json deleted file mode 100644 index ddbf34757..000000000 --- a/jacodb-analysis/src/test/resources/config_small.json +++ /dev/null @@ -1,789 +0,0 @@ -[ - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "System" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "getenv" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "Statement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "execute|executeQuery|executeUpdate|executeLargeUpdate" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "UNTRUSTED" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "INJECTION" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - } - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "Statement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "executeBatch|executeLargeBatch" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "UNTRUSTED" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "INJECTION" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - } - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "PreparedStatement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "execute|executeQuery|executeUpdate|executeLargeUpdate" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "UNTRUSTED" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "INJECTION" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - } - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "String" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "split" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "ResultAnyElement" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "String" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "concat" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - }, - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "StringBuilder" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "append" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "This" - } - }, - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - }, - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "StringBuilder" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "toString" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Statement" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "addBatch" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "This" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "ResultSet" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "get.*" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "UNTRUSTED" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Connection" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "prepareStatement" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.io" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "BufferedReader" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "readLine" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "UNTRUSTED" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.util" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Properties" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "getProperty" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "NULLNESS" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "System" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "getProperty" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "NULLNESS" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "source" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "DEBUG" - } - } - ] - }, - { - "_": "MethodSink", - "ruleNote": "DEBUG", - "cwe": [], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "sink" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "DEBUG" - } - } - } -] diff --git a/jacodb-analysis/src/test/resources/config_test.json b/jacodb-analysis/src/test/resources/config_test.json deleted file mode 100644 index 86260231e..000000000 --- a/jacodb-analysis/src/test/resources/config_test.json +++ /dev/null @@ -1,174 +0,0 @@ -[ - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "EXAMPLE" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "EXAMPLE" - } - } - ] - }, - { - "_": "Cleaner", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "RemoveMark", - "mark": { - "name": "REMOVE" - }, - "position": { - "_": "Argument", - "number": 0 - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyMark", - "mark": { - "name": "COPY" - }, - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - } -] diff --git a/jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json b/jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json deleted file mode 100644 index f2f31b240..000000000 --- a/jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*Message" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "readInt" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "UNTRUSTED" - } - } - ] - } -] diff --git a/jacodb-analysis/src/test/resources/pointerbench.jar b/jacodb-analysis/src/test/resources/pointerbench.jar deleted file mode 100644 index 7595762c01cf8f4499546e51bf2efb2718f40c9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32004 zcmeEuWmKG5(=EZJad+3??he7-0>Rzg0t9c|-5r7j_u%gC5Q4jg;BtF1Gv9r6KD$3J zYxOUlv-(+8yXx%PRn;%r}EAz!{*R9u89G}U|2puyZ9HuM z-Ztd_`hcjDA?S-N?aWyijcp8_ougFb?PrBid@{Hl@iL1Gix}$VXRG?);EF?4bx0ee zq~hY8V2_Hns@*DGbOyiJz`&8dz@a@sDTouGn1531KcS+qq9IOpH`^Z{%UI5Oc6|Pc z?^j}B!V=g(AFh>>UuaAoSOnlKYA7<+8AK9$5WXY(G!V;PP7PT3@qNs6s43{2=+>(d zzhkTMom3ts_Zr`3UhEC*+?F#cOGVQc@XbLxi?$ADyJdc~Xjcp;)}W2`^^z_kY{A}q z&z08i_RYJFoz|{fv1^ZI^vG@E?7k5h{&3pz+L?yVWr>LbM0(o(KAXIbCWIr98KjG0 zEzZk(ngtqlS-Hf#X9%QGPlYY-YIFVR&kkttKXXPzfB?P9Gr^g07%N)6nPsQk8ZvNQuVBc<;#zerd_?;h?zbo+dqS|q0)^2e#P1OP z*D#~~*D#a*4bu)z_Qs|ru1_me1MT3 z29t(3Hq9M%^H$mlcj-Drq%D#L&h{Z8U$oqXDFq$Kfy)ER-ydqwwWIBcQ?X(`tgfMS zDdQ|n=)K+fHbW;C?xknI_H}NO2X=X9(~GSdiI6XP?7_+&D3wCUCU;wmb{SM_>$GT& zGwY5Y@&v&paCV-t>Ui+*$eP;I>r-ZS7jFySb=dI5afLT-{xlbJWdcEy-SXO-nvU!% zPy}G9CF)PQQSQf{%n@lQQD7-_GOmxkMm{p`X{#M81-KSWB8hczfxD)rYAW}~t~z4xypX4_AAbA|QC!TJ&)(R;}}6EvtS zC3)2ap&sQV!Fl3+(C7_P3*98UU?ru^`9{)1Om)VV{6#R zsF-Q%hK$1LB_FWt+IL zNhjJUjQ?!Pb4~c1n`06dPovrmtzPZd7KBv;o5g4iHF~WhlEk=$w_as<4@05aMQ9Yj zU*1fOPMEK;J1i5s&z+>4E2%+qN?VJul9OD5^$PwQntM+VO5H(d9)$egqnY)O)Tw5z zh^~wx(6rvMAW_XGc9xcA>-+TZfY?Q#VRD_HDnhVL`-f5l&)aJTcOe-nN8g;X z!_K`_G>4Cfz*N=yn77s#r1qW+ot9s8@>K&8t)V2WmG zpy=hfR&$;Q2GD(`^vN3Nh%`}A++a?8QI>&hU0bmBCBci=#;%hIVwZ&{R+5bxl|Ib( zc#9&hS(Pmjh&1kJG&o-#*l{-61^fK*BWX5wDh}>4{i(}Uq_@!)#tAut(E)WvWEVK} z5FIuoz$la-ecTSFlf*64ySTzf^n}eQ3zF3{SE?!co%9uUpBq}u$fiOfcVJt6cwA@5 z<7uBzSQf?W6TxMcs#H|tM(jlF)I{u4G={EwG<#m!_;BqFlv5hJ8f9K#`Vi`+B%=sb zxrx_=LtTN*8v&EiLb(D#xj0@zWM+A7bJ#SA;FpAC<{0X}3PaT6`tsQm3Cwcrve4I9 z@AQcu%9uVbf@tc>edLiUQH~>QavWGB%HGLV^hyZ0S@49$oo{}FJBl%PNh%2LFMkL3 zf8-ye|2lcg+1oofvrs7f4s#!6dD&hNLzpctZdA6Oe^3^Zo!9QB@lgE=8-Q|@cjSYf z;wHP6NWt*JfGlzG9r@y2Se^2P$$Pidw5+t-z0>{0M;Je6b~6wqK(nd9t}zT~Wy#=d zv^_zAH%5)7$U8#p(`wF}5@^a8khx`qO-^Q__2-4$*RaOb45SL{S6z%mY{Xt|6l@W|SM z{V5eS1{_r|Tr2I4%M#Z^v=l#TOZXd2!rNClJ{B+D)WLv2csDo)rM`+lv^|>>mTlS$ zR61YQ^?L~1YX19V(&iU?{2MKY3}13&R;80T5ePcWUh)V}R;*Wg}#BN7=uPsRYWk{5?aGZDWcJ~ zSr+S-zt=c)EUod7i8)C15E0sPc$pJt#dVfb=BL%N!=mRh8ATo+rk$nx+LUTVG=m@N!1)WSe&9%uV%Tw>T*btq56$Ow5FvWn&<}B=+BCf)fj{94SrB7<9N5=LyLc!; zE`ez?i(+umFvPot?%kQwOhzBTnMCJitE@^g`cw8@_!ppVx%) ze}Fvi(#|@irkiwCNIlmr9Khm@sE<B( zC~C!PP;TD(V%Q5)O5@d;zY5EkZ_Ev#*;fufRtEI3Zb*59RVI(A8lia+P~#F70O51= z1EWZ3nnfrrG($em+bbiVP2aUULYRlfSx=N2gm1GS5oo?QO?&*}SmH|GW3KmYMDLCw zd{>@5Y&os=6BhBkOPb}yD$EqyZXBCg$@;U17IcQ|V#@ASB7n zCBerSp)z2FETEv09r=xl1tGf^`HLUivp@ zJH^Q#nfq(Ar-SEJ8*j#p^n!sbn8+;I;>y91D(Pe5@a?p6;mz57iQ)B9GRC}cf&TNj z_38V|-L<2=Q%JbH+1%Oa3@k(aGkAfuC-%#L_p_HL51;A`VX8cOi=@6?Gn{?7>_VNS z7NJ~m3^neuxsS$P7U{jIAS~z>8)TK+un$gxiZcm8R zAh$cMyjZXtrgG;8iaPeL?N+sHI@zykMS%~l>V@Ke@8*;~YT4ol+)2irQ}-3BKEaO8 zJ+?{7#u~<}9in6@$cuz`bq!RCdypz%xn}YHIHk&SJ~;-uDF?Dx;Fw2BwlIM3w=>=?|0Q@*x}WTb+AM9AT4h|cR*;`z71x(;3AWa&C!e|Ar#Z2 zM(a<+hH*Z6=OX_}r00pGX43alxUDWuYq?AZc@Dqm5eXJ~nY=J%xmY&_D+O%?ZkhT3 zp&D}}PoyEytcP5iRfR>P?oV-LXv*t+COd0_=b(7l>8Lm1!$Go!v2O4{8qMHqgk=ho zCxuV2nT1i#PbkI{KdFbQG~+LQDOShh=V=0p#$PY zeLP0@&wYM;%ecS%am)oad7;)%uc3ycRcX``&Vl z^8LJp@Zz&Qv1wT7LyJ}zwU3q4OZo;y7w%kvN36$-HR-#usK+yz4rs(CjCu|i1C|q? z9T60-Hgg?;QP}&CEa3~6ja>ujnzTV!Ud!N^mcKY zX+L;x?<-?wo*>ar5++lNXE9zFa-tdlA*ZFOoyRs<)XVp@`j##_BHs>As_Y{>xwbBSy_p6{eK4?3V^RK)AW;3a zCi8EkzyAQ$A6YY4W#czB=EZLD`3rz6H6uLoP;2n$h)U5wZmKV+P!%08jY4E6%NG7D zvNB;1>6^$@YhmPl6T_OVQ_SW!6LOyU<7ei1rq|i?<&RM=uwyMI;cl5X@@wOH$-M%b zjgS@a7Up?o)3hW^@mE@-`J=I(J9i3CsiZ}2Zn!%o-TvcBtOOgM1aIW{y!+)-QfpDQ z*4B6P$hT-|2SXJ4s%;2hqKQ}YEFTy0?5>7tu2cATvgLOSR4G=J$EH*!P2sOS?lh3c z$XCP3eXLdGx)pHJHA__TrB{gDy@6$|<^-4SAKY7nX56=?F5iWvj`gA{!tk*VAC%9rZq7&FbIZH^)8y?}6E?^+RDID+K4B(gn8TN&In+$9DaP=_(sdN}V1-XiOLI{C^JuL7J9Dny^z z|MIfKC4p>2FinT0zWr6McE0hWV^+$!P!@f}naH|APwJNl$@fZp*hw{_$g2K#Dh5W! zL6qSxwUIU-Pccr=dC>OY*x;7?Tt#>3-azUz9bAq@(>Ti=&>dc3sPK!1ZPFKettxf}G2>bZtJXyJ$|(zXSjwvu^rC@Z$fLUqOrZrK z@8R#%z<;b#DF1bpqGD?7>f~%`Z}%TXWw5f2EI6oEG1KL+9UVW@#0+wYXzXgr$0mjC zBk3J9aKm>o$%tB4f6x(-ni3PrCC1EJ1}6qLO?A$2p1958(cd7>0n`4B72EHI%5!32 ztr^kIk95UtGNjUnyXJb`Ycr-m3wV_Ot?1|jYoghmhOx+*Z~C|(s%?lO zyLc&i(m`~N0IGlklhh!*57D(JMZ+sLI|mEUh>74`M{^vnM!I39B`m^Qtp=r@xM2Qd zdJKbI?T(v@Q`0fms;aMbSJG z!Pu1CL=`O&NY7Ay@Rh>3K0Gv0xlB-LS>INz6FP8b{sfhZLmGcK-v`oe+0^io{MypI z&NEwXCtBRiK0Q5wv@Y&FM0P`NAhRSu+z`*hZyI(W-@^ihAm)2qPe{Q*gpp{aLfQQ` zY%!#`9!a(_(HfKk)r(O}R68_uTh%VT$)tW1qr2O6X_MMdS@Fs zIk;bE0{c%KOn7Xf!-da%``EF{YU|tRZYL0`pXibb%8@(@Dd*i99H+`!zBsk4z*J?Fks923VrLaNBKZ zK(aZGZNWWyN|1sp)$rF($O=HgpPROvB-dul7Nli|dp9XH774X)ex11HwsZYS;K1gU z<`a+v(fN>~NXX;-fbtGGn=TH+;>+SwezS3s3sYs2TA(khYAsp2u4-U3eMUqlsed)q z@RXW{s|&wtzfbEO3AD=V7Pe=8%6T5#5rW8Pwp^Rtu|hLzR0U!&?|f8YeA7T^FGs?% z)0H=;%_0nQHS+;JkZDL3=N6oT`9NS|`_R8Y+w+w`VR zWK!8(bVeb4WL309HeDyBs-F*ItUX#-7RT?-cD~t2BN1&!;T1W+*!<~IyNMIGMw@>; z7+Pr-AXXSpOjdLl8$SZO2r%WMh}vmD?>kP~co*pu5Jnx>g>irJY=)RGlDQ5{z+tETJB;N;nJab5?39 zSUEH)W}!?HK`hNk@sZJq)*;5A;ounUQ&MADK&2Ri^sIfa8>W zhM&i@Kcyx0=e`!40Ipli1s@?;cIxsigH}X%hrQ(ziZPDU?Z&B#-|xkT0-N#}vQ4c+ z*F&56R<`gMSMbxNay%b)yJjvEzKUi`r^ih+bp-g3iuKS9i$a%uj#Zlg2Q~k$Wm z%c=223;R5KH$25bh;wXv>K`&#eMFrL@vk6fAX|uID{mn0J6J^WG%Av)w9?d_18c$Y zOb+J6Bb=H_p&_`YhtHHJoi=$T0?5i-R7x`F)I3<()e|91MY~c1ur{ky>Xd~P09N-v5vv>iAyp*NBqz><>KCv37^}oP; z2X|^SWbKdZl6do-q7|McYIq|p5>TrF-pOP)0(?iAWU{a9-44u-ae(S8clTOoYJbE@ zC~ZDjGObXEb+h2nrTAxDVR{{B@OX|1t;xl~*w zYC|+Vo{MmTc4M_DdgZLxP*knx2;v$=4yEr~-VWgajiG^1Qq_`O3ugo?9YF_>3J*^{veSoVJI#=dp4Rrk$9+QJ)_XPU<^FLS+t2H>$#mEy234(; z0e^(FoP?xoUMeYTmIRCpYJLez;(%OzrhK=Qp+fF+*y+lqsy}CCGi@&ak46UnFJ-6N z$5E}8_e@2HD8uUQ=`Nf__U|SKbJ5OL{Dt!#zSXTyUCEDDp5he)PSP)X;PE@!XtRI~ zTBuS>tKe@}c+5I+l$%vRoTkCcG-`JM7QVU7-#+^mi zpguH$dSuqgFG%GF?Is!E@j^fFrjw;7>^u-V%_^6aoj<;uciB)><|C|w-)nf5Fjs+; zL%I;JP7dGq{SX*x00X6dF@ChAI~u~l@=Cju{h!{tMD#q3fDxTX`|GdA!PX^ybMnuA z2JNUp``qS3sD}yRgER<{jW`X$x9_oY265prsy>rI>mK5aQpXCjDrBinYZPo!h#|$G z`DoXC)Z@mR)cLk1+2wX?jeWa)2-N8Mp}Nw4sOLtg^nG|hoe6*00gL=n0@S5bjj z)O(lApTO1&fHfssPJ}uY^65d2J$AddYDi%U`B{AHC+SL=47yBd*p7X@@4K?=T{R|{ zU^fCwIVJmeJk^?;E|5|ZayTnz9rU)FhRgAod&Jx+{<=SbCNfrUwv)6$FQ4`;o4g4S zmp5T_&yGDWJBdY7TDT<3@VTxJ08B5q=8w?v8z^7Ge_ic+n2ov8tu5gN><(jisUUpIVFR?`1LL z@h9f8F6aZbT(PB<%Bk2p$N@-sIVoPBR8p3pkky&Uh~MhsKAfCqFK?sizPpp(#uSjU z3~|!0Grc;z&fGh)ogaTJE}nyBca<6;#gu9Fr?VfM;;35~7rqxM2taJ{{xD#Ms{<%1 zA;Y?70|ryrqrRMg5Sq+{NIPIrdmLu|8JHqU_u)x%Ai8iNZ(9MEfzURUm)->@a`m&T ziy_;!;1#pnQ}1lM?rP{Aj6|FJnC*EV=N85Jb1+Rb@V#IXbGL%v;nDz7?*qfQu~usR zPJ>FH!SlNsaAP9g$yZ^31ZBFm4bg}KwsSh9GJRUIS5~UF7LM6mld1DZ#VA^2R^C<4 zl0lc*57R+kW3JNPBxF&0rI3Yybe5A30Y1vBKTKrd*{g*$h^Y-wIj-tH8y_BBn2#{V zHr1n=Nzy#|?R^Toxk2mC77#7vYrI|jl4Cz0tH>Ao z*oI;I_RT;uY;uk0CnW1c&m4+5TDvKkPty?nPZwOj!D&|WbnFRKH~Ic?KmY5|E$n}) zbblM*vNd$F{xy^JuMd&@`$NBm!0Zfdex3e()aD!63B*PK^Q+8%w9|0Orr#S~`y>8i1B^9)KW4a{0y^!{`*6CJ`d8w$a>u zpzd4K?Y<`1s@7YQC<*jrC#?y?;O{4;!iPShtttZ4CP=--6p?f4Br$wkh`3o{z{w#k zf$Jb&Ml#b0xYTJ|OmxoUrabuiNIceyl`m0TWUX!tIItT6cR_A&?>8Uw26tq}*HTsF z!RI4WBRLG)RXWk!dwxnxIVrjp1}xYK8Kw4Wi!+o83E;-~xCVWo*p9ARHfu$9o;Im^ zk=~a1xKgHkr%EDSqtDQc+#_D}pxNqx=SHSTM7wQpS3b?4sx6MCfNENSCezsxbkvy> z6>A^SyiSOuST>N3OH^=QOX7?;NRabEZ#WlUF&E}rVeI~amIF8hLBu*Z2J_G{SWXDq z71b-%;=9a4Ql}K0nm#m1^sVU1*T80jFx7R60cJafAI4YF++4#gU;5mP)|NfQkG6D5 z3|dA{n%0bay4f>WsmxeXXeyRuNL~Z3DcybT?H_Jx2OPg0F?#=+65RRDwwwWi8rok% z?Vnq}e>$1T-pI<-*v0uTKtuKKLG$Nfkw35!uWSt}@q;JVDKe<+GPE1!Kii@uw66O- zl6BCCVg!gz!4xTNxXp5;aV{sFE^HJT(9+yNJSlIb4aYC2ND=LQYw2y@=d0uMeR+98 z{7$<@M`xi{9bkrANe5rI6^CR?$ZL9%e5pkee$23FE@FK_sqBbVWQc)0*bz2MB5;#% zL4#*T{ZhVfL*N(%b%TIeeo~bC{p=JWyegqrN(uin_eXbL#DZ&M6a|l37Aau2iI7y% zmmj@GoEp@!U|x`JYyFM&5OAe@;k6yPr)Lb#nCs7y2Bl&mzPKZ-`SZxbmb{S<0p zx3|(;d-R`aYN@wH;!E*P+3Psh=ljsXd!onpSF%L^h^L+G`^v)E?AI{mx@iu>#LoA&c)ReXBT=x; z31{j{M&%>LShMd$A53&K%UW(CF0bw0ZkPgL1$yRvkAwW1B4pAVw4gD?T<(yG`-a_d zjLmNSA=+0Jr(n1UDI#e#zXwF6aBnd_a%`qjzw}8vnEg`5GL0`n7eR4B1v1yaSH}Je zrh4~BCpRv=E$eaD!WBe{SHy>_`c|+sT-o}u|5JJ#h9i5L&Stq(vGZgP=v6Z+# znHNq?Mr*dYOB?7##r8gvZ7J(4w7W$GIlz!SKCL-T(Kv472RCIQZfQ^ndA96&O0H_; zt_@rsDco|53=4pFzPNSt?&f@sU$IZviumlpqetJ<4|5Kp`2q*2jGl#^om$TG2ICuE zeY$Iu7;ilU5Kq8@HXLidP;R<}v9RLRs$H?#{YSf%B*&7dFpCxdRKq78u304RAf$ta zP1|2!DqdEF*10Z-;%>&nZ;UEFOV7i zc)544GoPBt>6aj<_3)<3B6bUkhz&IW0pgu`(woF)96nO2xTFrL-0tIfSOeCrf3gG95DoI&z4N5o`(-F2Fje0(2~$p&?p8bZ(0-lq56yrpyK5KHoxvmJ+-a3zM#Mz z27UflDEecxEm%oju?IBThL9*)89+lrO!pBS>1IoQTLc{)JpcwaY|wVS%V;@WCDeBm zqT6B%G}?x1&V{2mFgo_NiO>Gq*#6=wj2|02;f~ToUVKQf0L--ut`Clv2(tyk*UD*SdXcl2WZ7DHCTD%bs=$K*rztiT2SxYR|2Cm2{Ug*!8KKRfKe<7_af23- zgyzf``#OfkCkd_opFs|HV5n;=GbeszsOvl-E#*ivJtI*YBR(||0t5AGSW#gNPL_TI z@-i=go)R~$KN27lG=@}dW?~>mA(}_7MEWOKsfM5%!P+bOYQ>45v7j|1p`k=?P&Ckn za)-Jg0c0p(yznNBu_h2#Cw^OU!s+s|UVISSk|Ysf{)AFa{u2FuM}4^5UG&v-&NmUHVj1_?|UGuIKTV7mOz!}8>yW>oM{m)92^1$ttCy(|)13gLi z_`D_Mysznz{J0zNOeE&*==Wp?VOmAJY~v=m0|*2~vhRi?gyG=psMC)}3;P|^%9)(t z9;wp%I&8{aWWNazhQHhF673fu$~5%-b_OVN89)?Ya<6I_jV+(|;?C9NI84HgOq9@# z{)ix}hETY&gI~WA zb+E3XO%~nDSIc`~i^i-1ZGknpoFmr$YmY~EUNa{$`#>5rE5N5v!S?BwYgTa;j^BaY zqW{Nr^{>l0T#)nrZhgnt-pS6?NzBmM^sgv6-CrFOF*Y`Jc2+WUvG}u%plWOVYiA;z z(>BWP_{gQBaeblK)~4dl65WsxHqZt>!5>3t&7{fJEL|!dp6t`@IqXPy0BCE1GCMnR(vXp=s5&MGCa>6D z+;Q8bF)&e2$Vka8(73zWqNRfy2hkQ)a38dz(+y8>MtC`ubc3O`<&V#zR=MbZJV;g_ zd=8MKhV?-`yOI*$i{1{U`8cpG;+3%#vi1{Kp zGi>+T3tLO|9g!G4S$^r^E2Gyp*W5^1m-VanU!tQ8l%5wsf&{vvl$N18hl&zZP@`U)^17-bxrmhUIc! z`bQ_tN5Qy~QwisHV?=ew;`BtUP76C)%j<;pU5Gs4bi4s=H8c>9c$^j4@dKMp_P=?# zO}x5)oH+gTdVh)D1vsL!6Hzp#h{_L_P7GoRN|VW}5DhLRgAxcX*~&#wMJ-P6VHdmo zdfYNC3uJ6>9>}G?&p;B(+5I@Nx}JOrN!+|np}25`|FvZRLNn921kJXMRBZX-q)l%J zvT>WEaU4kOp-|l?M$Mk$edQabLCEAn?miiH^VT&WUTv1tfAQg7%~FT|&g9`HdNx$l zIq#Em5KX2d@G?V;cFIgjQUOOD2kiq+8=6;H4|$}#q^0Ac@zC+{0@B8|S%R0&o)t#( zw`52<{-u0#;;&ogR%YZB%C7Sphf(dWmYBj7wm9!;ScUOks=$le`c;oFgykH1J};D#?U7tL%a z9gGJsJtCg6wZnz6E@91^G2})lcDPes4<6I6L(c(U;#dP*Lfnp?E9!i+LTMqi!Z=cF zftsTl9mg+u%T!n~Gh#B#E#BHYq$&@}=YVSi_;wofQU2c1{;xzP4w_dVOY^;0>?_7s zqdm!~rF{5B2V@#s7M04?ZrNSUfEIOyT<$<#G}T!QUwsvrFzwhm0HP6paYsqr!AuvN zTK1kK(wL|W4hGdk1E1id4z*R|@N9a4W#5@h;VQIm*7WCie?8cl&ysALq zVDoof+kdQk|C{0PM{h0Z&waI}1zQY%TLs~19%W9A&-k#lZ+OkvQ}bAG(8TVhqM^fe ztXD)SfW%vq7YHcQkvY%G1J371&=3KP%PpV{pNSutP2co8J72+=17!dZN@UIG-6jB4 zr52Ad2@z2iXx!NkV|^qdn{Cu+X7_YR&L8-bm?u&6m>Fhuj1GqP7H|X9y+#cVs?w4# z&8kZAC%okCW2yA&j!%~L&_ z+mBa&m}R?_KhM>oQVFoafxMve`ldcqyyvZE>$CXT>x(w6zI``@IiA?wM^)B2T+!^! zk5E9rfnWtPdUmMSvZ1QxsfZW#IL_{3Gi^ZWiKMOO>f#*G%(mP*+gN**EGT!+MwJ6C z<%6o{F=O7~!ihkM-B)(cpFl?12@LlnmQe2AMJ6@MwvJkLI-0{`Hzmu|be)wc3?Ef# zoyMjWjp>$_{g2oH-qvxkq9_gikcFrscYj^K87^eXM3clC5@S?Z*6d9lv4_@`Q7L1s z0TgUw95baCb1RcbGRAE|rZM4?4tpqGu`_tLy!v`z>yu`GNiyCDb9Vbu$tXTPS`zu- zNjUdMb{NRmu|2ExxI|jfG(q{7gf0(qX{v+5nGp*_d4fQn0(mg$c*DH0?^Mz)rhXW9 z(<2_G-usIt>tfavM4`8tBukeu)A0NhwG~}bO())f4*YIgf7uwQQ}B9XTbQB*jwVHD zMbNmz9d)7hCs(p60`i$nDP=ifA`zN{eu{^KG-)MK!j8hp#R!@+_zuDFgY54J7afn@ zZv}J2G2Vr`l_(cF$>sPbtyoG4(yvrUP6i;iZTCiJiat0*YB9_ylqAX7yR+7*Mf1GC z#=r6hYx4H;Zq-S`3XyA}_dRqenw{t;ye~9K{vt&+t56JuUxXxhWw-%{XK;bRN;#`J zO1ugE{KyBI8HG~HgH53gp&MUC5J|M+G0Ft`4-!j6)7-Dg!)`qNYN_;Ws>c2V1(h)L zUlm&a&7k_DOZYcI#WJ#*IutPi76+bC>z|9C>nA*w|Ccc}0&NWWp>{tzJL{4EmjBk} zH>nZI0KVLjf*G~90EgAlgk{(;yq67b*0J6I*z1hMv=z(TT|f}>HRydu_!vQmCma)Q zeqFNd{SN@*$Pks7$M7->t~SRg=LTUSVD|YlzQhOxdr2-fm+RuzqzLQD`FoMO`PF*ZB=*+sUg+u~DJ)u>=}rOnEXb^)GgqS~KgDWyU8N zP#db)S52B1foxfZ-)~gt*m1}@4)1Y+u@l`Sq2T~16`mnTiT8Sa-9yk4%Qi}hyUNXl zI-Fu9wMD1LA+6eTr@F4a?hIa<1aB+a+IE!QW#tTC1-#?EMBMLUNPUatUSA$oz zbS_r6fVDA(@@ssJp9HR~2ZJ&0TR`dRnb-i>M^k{)!6x&VhzOI|1BjhT634R=IY+FN zDRg4<0?4^C#VBmsKQrnT-pS3bvjW~O+E=__z6%PeSALHkBPb7vN|A(Gc|+lOJsXh% z_R1b``IhqQJ4L$6$c3Q;+9hOo(F2Oe@Ex!-^pRa~m%I#(foFKm&b%XNZR0Sd{7t~- z(F=EF7s@j_O#r$27X)sPYcOOersq;6jQr**Cz`-APajrq;1F(pC#j|Jae?unYF`;% zmJ5{uz_4&SsKjD`o1<87Mi%;`{G5x-0mp3EL$F?`qHt~#)`7HWeobQ({W6PZm_}JW zDO7#4IG@2uT{#Z!@gq!sSg|N#a%1R~N-emg{__+%~Fu_$A&* ztKgE6f(RZK%wGi{^IwrXNlQ~3lYgdoQEGo|iQO_r82H2M=|HyHHqmq0Loo$Iim6=W z0sByhi&q-}cJAY6$x@NNgYM{vQB(uwzKNG(0cZ@x^~=s?liojk%=a?0h=n@6A*utY z;U$%%$lu6|pi)|nNFPY6VZcwwswz3aNy4+y(huEBSSH77DHsKl)=&|k@*9O(_3Hwc zfUC7Ql1Du?Zmn6xy8`?28Dwd#)=pk2UZNd2(8k>z7r56C_?q1QyBrLIYg}@R&h++y zkID8n@S}Dd^n=*`+!)={TXfP+8`!oXo256mJyUMYw<``AFv+-glD4kQqQ&FiSmls` zXcwWiXAUAq?`^9-bs@JHI+xh8gDY~M#?lY8bDmnAWLlD0=m}fug7XMa2{1qxZMq4} zu3%hE)%uvTGP$ZnZqbi5z zgrC&vpl-{(7~1buCVA|tpQ-y?6GXGV5MLWk7@=M3_2Uthd4N`3iz2undJmRSg%A>o zAiVmOo+g1kpurO3XZKK2BD;{0V%y=Peuy&0=}7DTht3_frcX1F{=4Y1BFFXt zKia5PewH?)Yj;{WVtYP7z9aEfW`1u`i~Esni0$ffhGpp;o;b54Co1$09P09HFlK*x zPl<&K7sse6)T=|MLv*qnR337ro-o`(X8d>)MZeUZdFBZAFVmrMozeIuF2poV&0p1x z1jM~UecpY2!3@LRHKu6V{f<*g*ghlHD(W<^B{>ZEnX7>6eJAG`%`Jj02cQJx$sO@p zs#&o8pfT`2K}$XqBKoGEM`X8!bx*3DL{5+t{lvbDotKo*EMGuVNm%^66P99yQ#Stm zYd70&(laXtblX7xC58KMf&I_nC^g;RSF|@6Mm7EE!nK7BR_)&V=PRKU;Q(sBiy?-Q z3a;6u)HbhkwCRwsyb$Hcvs1={TKdWZEvqsG1~OcH&gW}9Z02TXH^0X4FfQo*4R^Le zg{4ViJW1zhh{S7RNw)J*S|FjTF?wA9P>vn+eZ4e9aBaTLX#I3zChOGz`#@3}^BY`I z9XEM%9D4lZjzt?a*L}>YbQ9@h+o+7kHI}{(V}R#7;An2*#xijCP(i(^o?N|-P}aS% zxxDSDF%MKz*tG!7GjYBhZs8T}e6gNm0PbIH2=U!ez~iiV?5C21d3jcAARBhgz)aF6-}M~k}V+iYVk*Bq%(KG&n6AIK#B^+7IO#|!8ZyHE^dMLM9>`%sf7u%l0f}pls3Q8LmlPX^} zNSh$T&#TQTg2q-)q+)wQ>i3cn8CHieVWcOE;=Qr%eR4fSg)BWYKi-IjE00``W( z#HX3wp2eE_0S2>0)6v5zb*48g(mCIl``ZdzhYWMo(b8qJG5oy(_3WZJTOa#oX(l3#4pRB`X(wez`ua`CVH^x>V81L8)|o-XuloXq}cHFzK8zK zvtS#UXK6Sg2`7)Q$gDqTLx>=8KNnza7?*b=N>{4Sn%EvC1{~4*NQW~3QQDXB2`&7D z5ZPE1PXzDsF4nx38@Vf7Fo8$xZL?I-3>iXj_{0;6A)Okx}YpbfEL6;pf!y?2Y*}wRS>se{%t{tgi**UEIAhIg4qj7bopGz3o1 z9Wb~LC>~A3?#Op>iE>hE5iwPA$D5Zth1Mu%GqFWusuoqzu=GV#y8)aUur}we?=b@e~lLWGhF_IzAt<+ z*66<6gLM23&ES$~OTsJ6rbIT}g^YtH`sBcuu6&|B>qgOcSMWq8j<#+7>i0U}VJD*8 z?bkl;d?v8J=A512yi&CxN8TdT<8B*Anfg3w#SjYs9f~qpp+32i^ zc=kSn5hq=>?R(kF*ASCP8XguQd$QIWc9I#5*t~Jh-^D|Ap;{OAq6e9CPuXwo-*D-k zHH?kZIDB0Yl?#AjfM4|rOCvQ*!X0=S!!gc)v6mB?z)l~nF%S0BA8cn_YjJ2Q12@BE z&G&@6%>QU1p%tB z(@MbXADmg~xYxdFIBx~c(np2V0Zt!?8+3Kh*Hg&Tk>ICG4x>6DR5QX?=G$XJKAXNP z2S9~8MZJ$B<15TWU+Ir)^Oj7=irvfCZ1 zGTV;;XO?N~5)%g)(9ayvZ!!Wyt(YVTigg2&1_dHfP94`uIKacm_F}2a<)&-Zu9QAJ zX^ri5|DwkYddX4#pkz4ncO!rQDEj>O@cpOe1KM<%Rl@l+aTZC(ZKv=xl60!p&K3JB zKn$FMf&xNlEEdOT?EkcO)=^P)-~X2wN_a?N0Hs5QZfWW6knU~}1q4LGA*DkUkQPyp zPU)5!T3P`K6%ddR5Pma0`Y?lvpYK|~<3HEsx-a+KyYIQ@p1t>buZ~3q897Ww1q1yP zOoHXI?(WKx&J71daG~(5ZSM*%3vAGD_}o2)YPwv<+2L`v5Dn|Jlj3;NflN%#LZ6uz z8>57*k5xmIL~jz4!Kkj3)fVH$bQ%8zr2bTxF@Yr%t}dM#~~19SaW*IHYQ6F5}Qy6fZ$XB*qzEV(mqfS*so>VCkc zL;kqrEp3Sh)H5DF#yyh+rEMuaml7;>usS&UW9mTBbl3n@H61na9s6&!5;#U?UVE`q zl~a?><2`qZdZNdjn!g=1=neP1HV|2^Ztkay`)IAl|6Iz`=PrkofGK;<6C&YuZot51 zV5V!(I%g#AouN5v$g!rDoZvJcAKO*1moCYU?o3i)6gm&qqPfN>*@rUQqn@4t6X*V4cX77ScC|F~_^;eVa|2qTh37YAJmnw)c+IZfOq^L?c_WG@%kF`K zypo*$ks3W`8}8IDOUSs8yC*MC2UK25G8=QV%s;_xH=hp!m2DzrrpjfvZ@u^1!MAUy zO@b7Ru7s;VVnPh+v?df5%rX`w1~BxBXmR0W(PO0fA|zvR<1s~$zL1B~6#sOdS=H`N(!wOTu3e;c zn7rZRn>79qr*-mNENPD#JMP|mp9+-Y*pI|jLV=c(X$lzwGykMr^KRxtS-_64sX(53 zzm7g*M*(D=8|DX;$Y=ZGxNFBm0|{`RE>}h-Tf2^O%fAejBARXiN`3&X0mHF$GMIIx z<(tVUjIU^E=lgDBKTw@6O&z;kXE>x`G&@(Ww4S&ZRemhQY9(~{8)aJsgZNDP@{@%~ z4)FtModX|`Yy3HG>;B5931F3TkxgFgf|K*=Xd~W^+CcW+V;zSRO2QF7g6U}c7tZL4 zPxJ$zPC4x@n)tqcg}s$lMn_~0hok~`NNt53&jdp$A@b9;LYV9joj>+2{hM?ua-1ff zILky$WCl)Y(I~rK>>$<9E7T|R=n^i`_(eE=M&#E)Be_U4_mQ&1@DI^yK4033lF4JC zU+8YTz`qnqb;&N$V_XhL7aWPrWGSysUvYVzDw>|iHc$Pvv|~)68l#9TQ49mI4K~UqhB_hgM2kSh8X=vq~`_vxa}Y zS~{N)K}9JZKz-C!u6)8Isn)a3dDTE=*cABeQDw=n-8jx3?@NPVx&oCT1D|Q$cJB+I z^4kk)F4u~jstu;Oh5g1ouhi`=(p1vGb~sOdIjwnr-gL|b+^p_URo#=ZDHR$hyJwj@<=ODn{&Ku(Qb z$fo96bh4{C@zyz#HH5_jLn1O8%Wh z`=SZHg`WYLS8}6W8=|{#r5b7IGD_n@>F52XuWF3&d`+Zw343#oUMiLWjLm7^mekJT zu6sTG1#*R9n_xGW6NFnoBlxJ!in98FP)@d2q+M?p+l{N9;DP~-(Yl9{Fb0%wlYHkK=#k7!3mLTlF6crA?`>u0BLYk9Ex?Mz4&PG*Q7j&0{n4@J^ zG~eSQE|B=df)-mdyTLe^m0PO_$b@RNzM=}1(<~`=(+{ttA0xSFTQ9{~sQt*Fa9A<= zpMx*@Ws}wH!mpY>XgceWn|!kB3`Euv^xBNL7d9G`N~6fwC)ZiPXxf>1DA?_Vu@uYj zEFC}+@5A;8D5%JJBdO{S+)2CMz(uSylxX~ zFTN+(cl!%bvr|i%saPl-$U+<}<pTG3FkRJDrHYZ3<4lnC>`{nN*9cZ#*43nS*PAJg??227DZlgr zJ3Sb{tMA2$$YicaoFfcjs8X#Gz?At*C!*AEW=(q`yS2?=uV82C8cwXfB?p4(1HC!xrU2EWe^wUm=4*#q5 zs_vKuOKeeFH_bG$`}q+Cirb%*-m|~nS8eEa2~T$fExU-+Ue(H=O*~E>fEahWYZc@O zVY}ZKDoQ8RTMkb(emPz94;FgS)8y_%qf3~bzO6bY_!HSgY01x2ULf^SX}9&4voX;b z)2MpN^G&?1R!2U7$gr2~1De`!vfqdcCF;mHXf9!Vf{3l>y!jO5=Ao_?g}Ks!qi^6! zSfvu@Paq`qapVT->}BeQltt7;1)0ylOB)z3WOB(C`(EJsOF6C)whTHv$&@n49(M@6 z9H+#O7DF|dVRAb)94RPQ4k~J@uoOAlFgzCsWi#Y^NRp?Bk_5K@ zg?jG(*SSx}cTrkvGmHP0%s<2XWA$ngZ_!qy+>lG1i9qZP#nhl;Vw#X2Zo9{W0_T*X)tk%oCrvw7 zke;}<8eYY(?{G>sQxX9^3D0OXQk=u}ovKhUb6+pKpFy)Yz)`OHx^_ppgbv~o2 z`fOL-(X71mBBRT7KTIgf=F?>ol5)of{?o3G#_SZN`tJ*qZq=LavA6LmJ}1z17ztw2 zL3bDyWxi^r-OL@Mkauv+4*ahFYduzkW!K5mFg%Z%Y_Ss*&bAg&IouCXG14ql6A)rr z`vzZc3&E6?uw_oig8GWs4OvkQ(=jGJl{MmbqXiH6KG21zSJYJ=A+1|HJl5KjY6_O< zih?LH4s>;5Et{IOe7-v2g`r{|`C^FSErW9`<#n_wc4B|V+o?x)F2?dNhbHARtUUO3 z-LmTbHSw@|;HVQIce|oIg>Orf|Lyh+8zNvb`^LPVRJPKl1YcGjiqoQsj`ONzY60YET0ao*krJf0y97;*! zwz09c**lDWId?(01?37Fh^#=6EB|V~UH-=|=4Fbpa9yVP2K^!jTU!oNELBUY_@~%< zWi_2KQ`jaK!QKXFEh&*k_-pRtjCqzJlIt6ra-frhUV2(mZmqSdOl$)D8X8~}iz+J3 z{PD%(D1-jCJxb>o_g<@}V$1cZknlb4w|YYIbSN&gg*~*AE;al1J9>uF%AyP_!LwJJg=4ssm)IhV9+P|h(ii;hCJ(m?g)a{zsJ-~$ ze}`3XyJOWfQjgakZxd@}xm`$GJYeS)P#hD-Yskoxhn!F>cl#fHHPM-)un~dM2ZWZ! zSEwDT8mX#o1qurQp88-HE+mBK)>y2(PRV_lEmy7bCc{`s;Z2)Ud2u9Pdo9swZmz-b z7u^=+QfV#M2#>IPTo2h>_7q@IRMrkIEwT@i9jglVY62SkS zn8GXWLa_Na-8Vip%jp7p7E4om113nqfy)_Sz{S1G3B_u(WwsV$9dSX#Nvtn)b*=J6 zV-<*1Nng({AxT;>ir{1KTnFJt#mQN+dl3;1VGM~z<9adN^2O8%&+H}DZ`K28QG1|FA>ulcIHwik58yv2qz{~W%W#i&Q>)=!eKen8?i2UIpjY%sj4;$`sTTx8oHXyh4WA7Q#uPN+98V;^@>xgz=H12{P9N#9 z8khnx0`HGLd$(Uu9`wd+kaS+R|if z`$Mh;V)ut#7NBT5WXu-F_iS6Ok0PIQeJL_@a*_63kQsGY9VPIzi8mc9I?5@Q(cSku z)Btl4HwRRcth=QR*9FMM-O?_3A9B~}v8%4qjjgK4Apz<-aw9nj&vxAR>fb6s3!3UU z*M<$kgz-}&-rR8GPSGyK9J>qT^Tya!r4ley%`N(@+2+y{)C&FY<@*ZKeCif4xz%JBU{G)EOU|&xHwkfWZBe2qL*08~4%88^ z3BX{VvFKCnA{y1aXqUm!8vk&io5!o_}Uoa0=ya!U*|m8PE@3 zsKkv6dS(&SA!^Tch+h)a;om}V4)MbaeypO{d~%bJ7Nqe815gBk9t$%#;@6e)P|Vc` zB=%izJSv2)q1K>lsJ;CO_EI_XBk0CX`jj#_(2Q@jrhZv;S#&^PZ~A!uE3|!tv~VIM zA|cqWS1Kk6&sNEr_F+687^Ecg(2>YOy*HvAU`9-<8;3{u8JI+?YZil*lq)pF;AwSc3`Qv}t-Yo#`w(3h`qBFxkTK1d;Q(RRd!@p+;xUsyZd+ zaTHX4zrn8@R9BO&QR|+nqFY&Y^Bvbvs^RFPk4C0mgu`2;os?FQrivYW=^S)Zv5d%Q z`E-S^*S_j;y5X~Vu!J*WXy1+W-abN=}LbZ8j&5AKGq;sG#d($2Xo)7NIYuFPH*7k9J}s-l}56QR-ri4Z1}&y(0~5 z7nGR8e<+E%S)3z3fve088bMf;Frj6h0 zJtT2SIGUiZ(#mr`E`ABF!#@|A9%deP7CL6`c4p>|RzJlg9%vfC-m1rW6NW}k%IstI zw|wNwrrL^_{9-DxwDCaXe)&W>U(9aT- zxBCQcHhk^>G+<)Vi1Mbz8X&l?ZNpE8mZOx&jIq~NA__j#z zi6T*;@@eyJ45LH`idv6~^lQj|oqA{VQ84FwBBS^lzx|V8;1>rfDIS@ zTlJ7F0{mOIi2&&yE09&i%2i{wZzAB=;?v5)C(mMdtYzyQyA-a(KLoW5l|+G~7}hy~ zCmK?n+J?g=NRKnWrK5{~T6^MH^+={`ZVeFlbV}BFSjd@7J+4drkX&=zy!i@e%RlMjyuG;^8qwUuTYLA_d9I=iw0NMRQBD-T}jI8&*eRr%8RK(pwxHPA#LGLBOG z=pp9AW|l&$-gg}t`?OZewto3L9D|bU=;iEP{z1DRE(4wpN^Wv*^;0?XAG+1)7bN-Q zcR69=Jaz`<@gAg(g*v27rc`5IjQHYeZyO`)5^~p|?Ep#Hjf7PivJ&4UY$d793Q;B< z?Oh=D-s-5*PHvxr&B`qX4kXl2@9RUDmH!$LLh!y@u0LMQr>+OfeS$9NB&&>cNt(B) z_x125SsnGDiDz+CVVHSTXp#~bxMfyDY|fsKX9~kOkFU)6WkN&sWn!&YcMYb%e6N5vw!DV;^~*)7N|gjUHI03=szpLMNh9?Sn+td( z+2y1b!!z_f?P>7v_vSuFPfytMN|%4wzDB%xM6+h=%5Dm*xXp|{w7v~ZHK&gy86np8 zr5Np6fB>waB}5DZ9U5=m4x%%9;7aj^rCnn3u;Y12HJdOm7*ukpGONIA?OArZ{2dhr zb8|d?kKV^#!2qyf)n%oEzWDW8<<-4sVKxNm3xL+Tf$6>050iJjXZv~gpI(|Gxp^lKXID8T1cN&~wTUCs zn+Do_#g5OF&?2qRWOX+0z28_AO^06+_%q-=91qXOX4M2uauf6yEixvr)=mKJsF6cjfAFw7}h~vMm zTdBGAMCPK9gO1tVZx_%{@AcDEGPVe51>K@SlM_Rc#M)^Y1} ze1sk%ocgo>)~WTd2Nu3*67A{P(4))HW!G;2XZvx%Uk(@$zHbd|bL(^jL1&BK0Kac? z{nB~qEEc{$2qIP;n)3g5?2nH|cr5JF!}qeFJ~b73bRF}zSj1K%XL0ad0AMO8r{g2^ zcK^o8e{uh=OV7gK)#edxyYSDSVgI!eIE#bV_eQksJ?=TUUu}ckWq4g@M7L=n_$}-| zE$1KMD0u5&KzO-cL?Fqf^MQZ3v+!!N^r!a$dK3$lLi)|EI8~7S*@yw&Mwqj}>un<1 zC<%?=os0baRfJboM6}W4@*jX_MLXebgk48?g*-&$6vf|=zqyhyB)nW1BGMY_mcRYk z|5^E?gyyW3@RC)CNEYb!&u@^ws-D4+f0{<34sT2P%w$i2P5E=sXD3DFJ#^{AUQ9 z64vS53iB6uwItY5{B*4U541DNSm&9F_&6_J{p0Wbsh|XZKVX)^YwO_#L*3;p z6JGZNktqpvgumGNL%!rJ6JE0dkx2}#H24eihknReCcL5pBC`mZi})Aj5ABPyOn4~* zMCKy2{_ZbK_0x&+PY*XNS>kl~^PFMA=Z~K?4Zac`wr6xYD$m3GB5`n*3t!R;t1&zs z#~Smw{Eq zzzy+p_%sGNs6o0J8Qg*_b^l@E ze)P|;TNoBTmWzlb&_4%zHvQnNweaygSk&%x3>uz;g$oOxCBnyl5Q%gqe(eQh*h;Nk}7XRCSar)AOziaTjY=|?Di}g9&-|y?f8x4EH k;5S1MpRhIC^WeX3+o>r6&|p`U7y3sL|H6fA2iV{K9|CRvr2qf` diff --git a/jacodb-analysis/src/test/resources/simplelogger.properties b/jacodb-analysis/src/test/resources/simplelogger.properties deleted file mode 100644 index de8ce921f..000000000 --- a/jacodb-analysis/src/test/resources/simplelogger.properties +++ /dev/null @@ -1,34 +0,0 @@ -# SLF4J's SimpleLogger configuration file -# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. - -# Default logging detail level for all instances of SimpleLogger. -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, defaults to "info". -org.slf4j.simpleLogger.defaultLogLevel=info - -# Logging detail level for a SimpleLogger instance named "xxxxx". -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=debug - -# Set to true if you want the current date and time to be included in output messages. -# Default is false, and will output the number of milliseconds elapsed since startup. -org.slf4j.simpleLogger.showDateTime=true - -# The date and time format to be used in the output messages. -# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. -# If the format is not specified or is invalid, the default format is used. -# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. -org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss - -# Set to true if you want to output the current thread name. -# Defaults to true. -org.slf4j.simpleLogger.showThreadName=false - -# Set to true if you want the Logger instance name to be included in output messages. -# Defaults to true. -org.slf4j.simpleLogger.showLogName=true - -# Set to true if you want the last component of the name to be included in output messages. -# Defaults to false. -org.slf4j.simpleLogger.showShortLogName=true diff --git a/jacodb-cli/build.gradle.kts b/jacodb-cli/build.gradle.kts deleted file mode 100644 index f308337c3..000000000 --- a/jacodb-cli/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -plugins { - kotlin("plugin.serialization") -} - -dependencies { - api(project(":jacodb-api-jvm")) - api(project(":jacodb-core")) - api(project(":jacodb-analysis")) - - implementation(Libs.kotlin_logging) - implementation(Libs.kotlinx_cli) - implementation(Libs.kotlinx_serialization_json) - - testImplementation(testFixtures(project(":jacodb-core"))) -} diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt deleted file mode 100644 index 7591cbc26..000000000 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.cli - -import kotlinx.cli.ArgParser -import kotlinx.cli.ArgType -import kotlinx.cli.default -import kotlinx.cli.required -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToStream -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.toSarif -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.analysis.unused.toSarif -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcClassProcessingTask -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.impl.jacodb -import java.io.File -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class AnalysisMain { - fun run(args: List) = main(args.toTypedArray()) -} - -typealias AnalysesOptions = Map - -@Serializable -data class AnalysisConfig(val analyses: Map) - -fun launchAnalysesByConfig( - config: AnalysisConfig, - graph: JcApplicationGraph, - methods: List, -): List>> = with(JcTraits) { - return config.analyses.mapNotNull { (analysis, options) -> - val unitResolver = options["UnitResolver"]?.let { - UnitResolver.getByName(it) - } ?: SingletonUnitResolver - - when (analysis) { - "NPE" -> { - val manager = NpeManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif(manager.vulnerabilityTraceGraph(it)) } - } - - "Unused" -> { - val manager = UnusedVariableManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif() } - } - - "SQL" -> { - val manager = TaintManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif(manager.vulnerabilityTraceGraph(it)) } - } - - else -> { - logger.error { "Unknown analysis type: $analysis" } - return@mapNotNull null - } - } - } -} - -@OptIn(ExperimentalSerializationApi::class) -fun main(args: Array) { - val parser = ArgParser("taint-analysis") - val configFilePath by parser.option( - ArgType.String, - fullName = "analysisConf", - shortName = "a", - description = "File with analysis configuration in JSON format" - ).required() - val dbLocation by parser.option( - ArgType.String, - fullName = "dbLocation", - shortName = "l", - description = "Location of SQLite database for storing bytecode data" - ) - val startClasses by parser.option( - ArgType.String, - fullName = "start", - shortName = "s", - description = "classes from which to start the analysis" - ).required() - val outputPath by parser.option( - ArgType.String, - fullName = "output", - shortName = "o", - description = "File where analysis report (in SARIF format) will be written. File will be created if not exists. Existing file will be overwritten." - ).default("report.sarif") - val classpath by parser.option( - ArgType.String, - fullName = "classpath", - shortName = "cp", - description = "Classpath for analysis. Used by JacoDB." - ).default(System.getProperty("java.class.path")) - - parser.parse(args) - - val outputFile = File(outputPath) - - if (outputFile.exists() && outputFile.isDirectory) { - throw IllegalArgumentException("Provided path for output file is directory, please provide correct path") - } else if (outputFile.exists()) { - logger.info { "Output file $outputFile already exists, results will be overwritten" } - } - - val configFile = File(configFilePath) - if (!configFile.isFile) { - throw IllegalArgumentException("Can't find provided config file $configFilePath") - } - val config = Json.decodeFromString(configFile.readText()) - - val classpathAsFiles = classpath.split(File.pathSeparatorChar).sorted().map { File(it) } - - val cp = runBlocking { - val jacodb = jacodb { - loadByteCode(classpathAsFiles) - dbLocation?.let { - persistent(it) - } - installFeatures(InMemoryHierarchy, Usages) - } - jacodb.classpath(classpathAsFiles) - } - JcTraits.cp = cp - - val startClassesAsList = startClasses.split(";") - val startJcClasses = ConcurrentHashMap.newKeySet() - cp.executeAsync(object : JcClassProcessingTask { - override fun process(clazz: JcClassOrInterface) { - if (startClassesAsList.any { clazz.name.startsWith(it) }) { - startJcClasses.add(clazz) - } - } - }).get() - val startJcMethods = startJcClasses.flatMap { it.declaredMethods }.filter { !it.isPrivate } - - val graph = runBlocking { - cp.newApplicationGraphForAnalysis() - } - - val vulnerabilities = launchAnalysesByConfig(config, graph, startJcMethods).flatten() - val report = sarifReportFromVulnerabilities(vulnerabilities) - val prettyJson = Json { - prettyPrint = true - } - - outputFile.outputStream().use { fileOutputStream -> - prettyJson.encodeToStream(report, fileOutputStream) - } -} diff --git a/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt b/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt deleted file mode 100644 index 3e9976978..000000000 --- a/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.cli - -import org.jacodb.testing.analysis.NpeExamples -import org.junit.jupiter.api.Test - -class CliTest { - @Test - fun `test basic analysis cli api`() { - val args = listOf( - "-a", CliTest::class.java.getResource("/config.json")?.file ?: error("Can't find file with config"), - "-s", NpeExamples::class.java.name - ) - AnalysisMain().run(args) - } -} \ No newline at end of file diff --git a/jacodb-cli/src/test/resources/config.json b/jacodb-cli/src/test/resources/config.json deleted file mode 100644 index 21a1020ab..000000000 --- a/jacodb-cli/src/test/resources/config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "analyses": { - "NPE": {}, - "Unused": { - "UnitResolver": "class" - }, - "SQL": {} - } -} \ No newline at end of file diff --git a/jacodb-ets/build.gradle.kts b/jacodb-ets/build.gradle.kts index 2d18f61d5..82280243b 100644 --- a/jacodb-ets/build.gradle.kts +++ b/jacodb-ets/build.gradle.kts @@ -14,8 +14,6 @@ dependencies { implementation(Libs.jdot) testImplementation(kotlin("test")) - testImplementation(project(":jacodb-analysis")) - testImplementation(testFixtures(project(":jacodb-core"))) testImplementation(Libs.mockk) } diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt index 4baf176a8..9b7180523 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt @@ -81,3 +81,27 @@ fun loadEtsFileAutoConvert(tsPath: Path): EtsFile { return etsFile } } + +fun loadEtsProjectAutoConvert( + path: Path, + loadEntrypoints: Boolean = false, + useArkAnalyzerTypeInference: Int? = 1, +): EtsScene { + val irFolderPath = generateEtsIR( + path, + isProject = true, + loadEntrypoints = loadEntrypoints, + useArkAnalyzerTypeInference = useArkAnalyzerTypeInference, + ) + val files = irFolderPath + .walk() + .filter { it.extension == "json" } + .map { + it.inputStream().use { stream -> + val etsFileDto = EtsFileDto.loadFromJson(stream) + convertToEtsFile(etsFileDto) + } + } + .toList() + return EtsScene(files) +} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt deleted file mode 100644 index 158659ea0..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.ets.test - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintAnalysisOptions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.EtsTraits -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsScene -import org.jacodb.ets.test.utils.loadEtsFileFromResource -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import kotlin.io.path.exists -import kotlin.io.path.toPath -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -@Disabled("Have several issues with EtsIR") -class EtsIfds { - - companion object : EtsTraits { - private const val BASE_PATH = "/etsir/samples" - - private fun loadSample(programName: String): EtsFile { - return loadEtsFileFromResource("$BASE_PATH/${programName}.ts.json") - } - } - - private fun projectAvailable(): Boolean { - val resource = object {}::class.java.getResource("/samples/source/project1")?.toURI() - return resource != null && resource.toPath().exists() - } - - @Test - fun `test taint analysis on MethodCollision`() { - val file = loadSample("MethodCollision") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "isSame" && method.signature.enclosingClass.name == "Foo") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "log") add( - TaintMethodSink( - method = method, - ruleNote = "CUSTOM SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods }.filter { it.name == "main" } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @Test - fun `test taint analysis on TypeMismatch`() { - val file = loadSample("TypeMismatch") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "add") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ) - ) - ) - if (method.name == "log") add( - TaintMethodSink( - method = method, - ruleNote = "CUSTOM SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(1), mark = TaintMark("TAINT")) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @Disabled("TODO: Sink should be detected in the 'good' method") - @Test - fun `test taint analysis on DataFlowSecurity`() { - val file = loadSample("DataFlowSecurity") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "samples/source") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "sink") add( - TaintMethodSink( - method = method, - ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - if (method.name == "pass") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - CopyAllMarks(from = Argument(0), to = Result) - ), - ) - ) - if (method.name == "validate") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - RemoveMark(mark = TaintMark("TAINT"), position = Argument(0)) - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val goodMethod = project.classes.flatMap { it.methods }.single { it.name == "good" } - logger.info { "good() method: $goodMethod" } - val goodSinks = manager.analyze(listOf(goodMethod), timeout = 60.seconds) - logger.info { "Sinks in good(): $goodSinks" } - Assertions.assertTrue(goodSinks.isEmpty()) - - val badMethod = project.classes.flatMap { it.methods }.single { it.name == "bad" } - logger.info { "bad() method: $badMethod" } - val badSinks = manager.analyze(listOf(badMethod), timeout = 60.seconds) - logger.info { "Sinks in bad(): $badSinks" } - Assertions.assertTrue(badSinks.isNotEmpty()) - } - - @Test - fun `test taint analysis on case1 - untrusted loop bound scenario`() { - val file = loadSample("cases/case1") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @Test - fun `test taint analysis on case2 - untrusted array buffer size scenario`() { - val file = loadSample("cases/case2") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - TaintAnalysisOptions.UNTRUSTED_ARRAY_SIZE_SINK = true - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - // TODO(): support AnyArgument Position type for more flexible configs - @Test - fun `test taint analysis on case3 - send plain information with sensitive data`() { - val file = loadSample("cases/case3") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "getPassword") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "publishEvent") add( - TaintMethodSink( - method = method, ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(1), mark = TaintMark("TAINT")) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @EnabledIf("projectAvailable") - @Test - fun `test taint analysis on AccountManager`() { - val file = loadEtsFileFromResource("/etsir/project1/entry/src/main/ets/base/account/AccountManager.ts.json") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - // adhoc taint second argument (cursor: string) - if (method.name == "taintSink") add( - TaintMethodSink( - method = method, - cwe = listOf(), - ruleNote = "SINK", - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")), - ) - ) -// // encodeURI* -// if (method.name.startsWith("encodeURI")) add( -// TaintMethodSource( -// method = method, -// condition = ContainsMark(position = Argument(0), mark = TaintMark("UNSAFE")), -// actionsAfter = listOf( -// RemoveMark(position = Result, mark = TaintMark("UNSAFE")), -// ), -// ) -// ) -// // RequestOption.setUrl -// if (method.name == "setUrl") add( -// TaintMethodSource( -// method = method, -// condition = ConstantTrue, -// actionsAfter = listOf( -// CopyMark( -// mark = TaintMark("UNSAFE"), -// from = Argument(0), -// to = Result -// ), -// ), -// ) -// ) -// // HttpManager.requestSync -// if (method.name == "requestSync") add( -// TaintMethodSink( -// method = method, -// ruleNote = "Unsafe request", // FIXME -// cwe = listOf(), // FIXME -// condition = ContainsMark(position = Argument(0), mark = TaintMark("UNSAFE")) -// ) -// ) - // SyncUtil.requestGet - if (method.name == "requestGet") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf(AssignMark(position = Result, mark = TaintMark("TAINT"))) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methodNames = setOf( - "getDeviceIdListWithCursor", - "requestGet", - "taintRun", - "taintSink" - ) - - val methods = project.classes.flatMap { it.methods }.filter { it.name in methodNames } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt deleted file mode 100644 index e999da8ce..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.ets.test - -import org.jacodb.ets.test.utils.getConfigForMethod -import org.jacodb.ets.test.utils.loadEtsFileFromResource -import org.jacodb.ets.test.utils.loadRules -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.analysis.util.EtsTraits -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsScene -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import java.nio.file.Files -import java.nio.file.Paths -import kotlin.io.path.exists -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class EtsProjectAnalysis { - private var tsLinesSuccess = 0L - private var tsLinesFailed = 0L - private var analysisTime: Duration = Duration.ZERO - private var totalPathEdges = 0 - private var totalSinks: MutableList> = mutableListOf() - - companion object : EtsTraits { - private const val SOURCE_PROJECT_PATH = "/project1" - private const val PROJECT_PATH = "/etsir/project1" - private const val START_PATH = "/entry/src/main/ets" - private const val BASE_PATH = PROJECT_PATH + START_PATH - private const val SOURCE_BASE_PATH = SOURCE_PROJECT_PATH + START_PATH - - private fun loadFromProject(filename: String): EtsFile { - return loadEtsFileFromResource("$BASE_PATH/$filename.json") - } - - private fun countFileLines(path: String): Long { - val stream = object {}::class.java.getResourceAsStream(path) - ?: error("Resource not found: $path") - stream.bufferedReader().use { reader -> - return reader.lines().count() - } - } - - val rules = loadRules("config1.json") - } - - private fun projectAvailable(): Boolean { - val resource = object {}::class.java.getResource(PROJECT_PATH)?.toURI() - return resource != null && Paths.get(resource).exists() - } - - @EnabledIf("projectAvailable") - @Test - fun processAllFiles() { - val baseDirUrl = object {}::class.java.getResource(BASE_PATH) - val baseDir = Paths.get(baseDirUrl?.toURI() ?: error("Resource not found")) - Files.walk(baseDir) - .filter { it.toString().endsWith(".json") } - .map { baseDir.relativize(it).toString().replace("\\", "/").substringBeforeLast('.') } - .forEach { filename -> - handleFile(filename) - } - makeReport() - } - - private fun makeReport() { - logger.info { "Analysis Report On $PROJECT_PATH" } - logger.info { "====================" } - logger.info { "Total files processed: ${tsLinesSuccess + tsLinesFailed}" } - logger.info { "Successfully processed lines: $tsLinesSuccess" } - logger.info { "Failed lines: $tsLinesFailed" } - logger.info { "Total analysis time: $analysisTime" } - logger.info { "Total path edges: $totalPathEdges" } - logger.info { "Found sinks: ${totalSinks.size}" } - - if (totalSinks.isNotEmpty()) { - totalSinks.forEachIndexed { idx, sink -> - logger.info { - """Detailed Sink Information: - | - |Sink ID: $idx - |Statement: ${sink.sink.statement} - |Fact: ${sink.sink.fact} - |Condition: ${sink.rule?.condition} - | - """.trimMargin() - } - } - } else { - logger.info { "No sinks found." } - } - logger.info { "====================" } - logger.info { "End of report" } - } - - private fun handleFile(filename: String) { - val fileLines = countFileLines("$SOURCE_BASE_PATH/$filename") - try { - logger.info { "Processing '$filename'" } - val file = loadFromProject(filename) - val project = EtsScene(listOf(file)) - val startTime = System.currentTimeMillis() - runAnalysis(project) - val endTime = System.currentTimeMillis() - analysisTime += (endTime - startTime).milliseconds - tsLinesSuccess += fileLines - } catch (e: Exception) { - logger.warn { "Failed to process '$filename': $e" } - logger.warn { e.stackTraceToString() } - tsLinesFailed += fileLines - } - } - - private fun runAnalysis(project: EtsScene) { - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = { method -> getConfigForMethod(method, rules) }, - ) - val methods = project.classes.flatMap { it.methods } - val sinks = manager.analyze(methods, timeout = 10.seconds) - totalPathEdges += manager.runnerForUnit.values.sumOf { it.getPathEdges().size } - totalSinks += sinks - } -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt deleted file mode 100644 index 9c68b0737..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.ets.test - -import org.jacodb.ets.base.EtsArrayType -import org.jacodb.ets.base.EtsAssignStmt -import org.jacodb.ets.base.EtsCallStmt -import org.jacodb.ets.base.EtsClassType -import org.jacodb.ets.base.EtsInstLocation -import org.jacodb.ets.base.EtsInstanceCallExpr -import org.jacodb.ets.base.EtsLocal -import org.jacodb.ets.base.EtsReturnStmt -import org.jacodb.ets.base.EtsStringType -import org.jacodb.ets.base.EtsThis -import org.jacodb.ets.base.EtsVoidType -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.graph.EtsCfg -import org.jacodb.ets.model.EtsClassImpl -import org.jacodb.ets.model.EtsClassSignature -import org.jacodb.ets.model.EtsFieldImpl -import org.jacodb.ets.model.EtsFieldSignature -import org.jacodb.ets.model.EtsFieldSubSignature -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsFileSignature -import org.jacodb.ets.model.EtsMethodImpl -import org.jacodb.ets.model.EtsMethodSignature -import org.jacodb.ets.model.EtsScene -import kotlin.test.Test -import kotlin.test.assertEquals - -class EtsSceneTest { - - @Test - fun `test create EtsScene with multiple files`() { - val fileCatSignature = EtsFileSignature( - projectName = "TestProject", - fileName = "cat.ts", - ) - val classCatSignature = EtsClassSignature( - name = "Cat", - file = fileCatSignature, - namespace = null, - ) - val fieldName = EtsFieldImpl( - signature = EtsFieldSignature( - enclosingClass = classCatSignature, - sub = EtsFieldSubSignature( - name = "name", - type = EtsStringType, - ) - ) - ) - val methodMeow = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classCatSignature, - name = "meow", - parameters = emptyList(), - returnType = EtsVoidType, - ) - ) - val ctorCat = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classCatSignature, - name = "constructor", - parameters = emptyList(), - returnType = EtsVoidType, - ), - ) - val classCat = EtsClassImpl( - signature = classCatSignature, - fields = listOf(fieldName), - methods = listOf(methodMeow), - ctor = ctorCat, - ) - val fileCat = EtsFile( - signature = fileCatSignature, - classes = listOf(classCat), - namespaces = emptyList(), - ) - - val fileBoxSignature = EtsFileSignature( - projectName = "TestProject", - fileName = "box.ts", - ) - val classBoxSignature = EtsClassSignature( - name = "Box", - file = fileBoxSignature, - namespace = null, - ) - val fieldCats = EtsFieldImpl( - signature = EtsFieldSignature( - enclosingClass = classBoxSignature, - sub = EtsFieldSubSignature( - name = "cats", - type = EtsArrayType(EtsClassType(classCatSignature), 1), - ) - ) - ) - val methodTouch = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classBoxSignature, - name = "touch", - parameters = emptyList(), - returnType = EtsVoidType, - ) - ).also { - var index = 0 - val stmts = listOf( - EtsAssignStmt( - location = EtsInstLocation(it, index++), - lhv = EtsLocal("this", EtsClassType(classBoxSignature)), - rhv = EtsThis(EtsClassType(classBoxSignature)), - ), - EtsCallStmt( - location = EtsInstLocation(it, index++), - expr = EtsInstanceCallExpr( - instance = EtsLocal("this", EtsClassType(classBoxSignature)), - method = methodMeow.signature, - args = emptyList(), - ) - ), - EtsReturnStmt( - location = EtsInstLocation(it, index++), - returnValue = null, - ) - ) - check(index == stmts.size) - val successors = mapOf( - stmts[0] to listOf(stmts[1]), - stmts[1] to listOf(stmts[2]), - ) - it._cfg = EtsCfg( - stmts = stmts, - successorMap = successors, - ) - } - val ctorBox = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classBoxSignature, - name = "constructor", - parameters = emptyList(), - returnType = EtsVoidType, - ), - ) - val classBox = EtsClassImpl( - signature = classBoxSignature, - fields = listOf(fieldCats), - methods = listOf(methodTouch), - ctor = ctorBox, - ) - val fileBox = EtsFile( - signature = fileBoxSignature, - classes = listOf(classBox), - namespaces = emptyList(), - ) - - val project = EtsScene(files = listOf(fileCat, fileBox)) - val graph = EtsApplicationGraphImpl(project) - - val callStmt = project.classes - .asSequence() - .flatMap { it.methods } - .filter { it.name == "touch" } - .flatMap { it.cfg.stmts } - .filterIsInstance() - .first() - assertEquals(methodMeow, graph.callees(callStmt).first()) - } -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt deleted file mode 100644 index 2826c4207..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.ets.test - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.EtsTraits -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsScene -import org.jacodb.ets.test.utils.loadEtsFileFromResource -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class EtsTaintAnalysisTest { - - companion object : EtsTraits { - private const val BASE_PATH = "/samples/etsir/ast" - - private const val DECOMPILED_PATH = "/decompiled" - - private fun loadFromProject(name: String): EtsFile { - return loadEtsFileFromResource("$BASE_PATH/$name.ts.json") - } - - private fun loadDecompiled(name: String): EtsFile { - return loadEtsFileFromResource("$DECOMPILED_PATH/$name.abc.json") - } - - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "source") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "sink") add( - TaintMethodSink( - method = method, - ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - if (method.name == "pass") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - CopyAllMarks(from = Argument(0), to = Result) - ), - ) - ) - if (method.name == "validate") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - RemoveMark(mark = TaintMark("TAINT"), position = Argument(0)) - ), - ) - ) - } - rules.ifEmpty { null } - } - } - - fun runTaintAnalysis(project: EtsScene) { - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods }.filter { it.name == "bad" } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - assertTrue(sinks.isNotEmpty()) - } - - @Test - fun `test taint analysis`() { - val file = loadFromProject("TaintAnalysis") - val project = EtsScene(files = listOf(file)) - runTaintAnalysis(project) - } - - @Disabled("Need to update the EtsIR-ABC json file") - @Test - fun `test taint analysis on decompiled file`() { - val file = loadDecompiled("TaintAnalysis") - val project = EtsScene(files = listOf(file)) - runTaintAnalysis(project) - } -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt index d82bb1b61..21da10fd0 100644 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt +++ b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt @@ -23,7 +23,6 @@ import org.jacodb.ets.utils.dumpDot import org.jacodb.ets.utils.render import org.jacodb.ets.utils.resolveSibling import org.jacodb.ets.utils.toText -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.Path import kotlin.io.path.div import kotlin.io.path.name @@ -79,7 +78,6 @@ object DumpEtsFileToDot { /** * Visualize classes and methods in [EtsFileDto] and [EtsFile] from directory. */ -@OptIn(ExperimentalPathApi::class) object DumpEtsFilesToDot { // private const val ETSIR = "/projects/applications_app_samples/etsir/ast/ArkTSDistributedCalc" // private val DOT_DIR = Path("generated/projects/applications_app_samples/Calc/dot") diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt deleted file mode 100644 index ac18fd3d6..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.ets.test.utils - -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule -import org.jacodb.api.common.CommonMethod -import org.jacodb.taint.configuration.NameExactMatcher -import org.jacodb.taint.configuration.NamePatternMatcher -import org.jacodb.taint.configuration.SerializedTaintCleaner -import org.jacodb.taint.configuration.SerializedTaintConfigurationItem -import org.jacodb.taint.configuration.SerializedTaintEntryPointSource -import org.jacodb.taint.configuration.SerializedTaintMethodSink -import org.jacodb.taint.configuration.SerializedTaintMethodSource -import org.jacodb.taint.configuration.SerializedTaintPassThrough -import org.jacodb.taint.configuration.TaintCleaner -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintEntryPointSource -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.jacodb.taint.configuration.actionModule -import org.jacodb.taint.configuration.conditionModule - -private val json = Json { - classDiscriminator = "_" - serializersModule = SerializersModule { - include(conditionModule) - include(actionModule) - } -} - -fun loadRules(configFileName: String): List { - val configResource = object {}::class.java.getResourceAsStream("/$configFileName") - ?: error("Could not load config from '$configFileName'") - val configJson = configResource.bufferedReader().readText() - val rules: List = json.decodeFromString(configJson) - // println("Loaded ${rules.size} rules from '$configFileName'") - // for (rule in rules) { - // println(rule) - // } - return rules -} - -fun getConfigForMethod( - method: CommonMethod, - rules: List, -): List? { - val res = buildList { - for (item in rules) { - val matcher = item.methodInfo.functionName - if (matcher is NameExactMatcher) { - if (method.name == matcher.name) add(item.toItem(method)) - } else if (matcher is NamePatternMatcher) { - if (method.name.matches(matcher.pattern.toRegex())) add(item.toItem(method)) - } - } - } - return res.ifEmpty { null } -} - -fun SerializedTaintConfigurationItem.toItem(method: CommonMethod): TaintConfigurationItem { - return when (this) { - is SerializedTaintEntryPointSource -> TaintEntryPointSource( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - - is SerializedTaintMethodSource -> TaintMethodSource( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - - is SerializedTaintMethodSink -> TaintMethodSink( - method = method, - ruleNote = ruleNote, - cwe = cwe, - condition = condition - ) - - is SerializedTaintPassThrough -> TaintPassThrough( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - - is SerializedTaintCleaner -> TaintCleaner( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - } -} diff --git a/jacodb-examples/build.gradle.kts b/jacodb-examples/build.gradle.kts deleted file mode 100644 index 1d630faf3..000000000 --- a/jacodb-examples/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -dependencies { - api(project(":jacodb-api-jvm")) - api(project(":jacodb-core")) - api(project(":jacodb-analysis")) - - implementation(Libs.slf4j_simple) - implementation(Libs.soot_utbot_fork) - implementation(Libs.kotlinx_coroutines_reactor) -} - -tasks.create("runJacoDBPerformanceAnalysis") { - classpath = sourceSets.main.get().runtimeClasspath - mainClass.set("org.jacodb.examples.analysis.PerformanceMetricsKt") -} - -tasks.create("runSootPerformanceAnalysis") { - classpath = sourceSets.main.get().runtimeClasspath - mainClass.set("org.jacodb.examples.analysis.SootPerformanceMetricsKt") -} diff --git a/jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java b/jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java deleted file mode 100644 index acb840cb5..000000000 --- a/jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.examples; - -import org.jacodb.api.jvm.*; -import org.jacodb.api.jvm.ext.JcClasses; -import org.jacodb.impl.JacoDB; -import org.jacodb.impl.JcSettings; -import org.objectweb.asm.tree.MethodNode; - -import java.io.File; -import java.util.Arrays; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; - -public class JavaReadMeExamples { - - private static JcClasspath classpath = null; - private static JcDatabase db = null; - - private static File lib1 = new File("1"); - private static File lib2 = new File("2"); - private static File buildDir = new File("3"); - - public static void getStringFields() throws Exception { - JcDatabase database = JacoDB.async(new JcSettings().useProcessJavaRuntime()).get(); - JcClassOrInterface clazz = database.asyncClasspath(emptyList()).get().findClassOrNull("java.lang.String"); - System.out.println(clazz.getDeclaredFields()); - } - - public static MethodNode findNormalDistribution() throws Exception { - File commonsMath32 = new File("commons-math3-3.2.jar"); - File commonsMath36 = new File("commons-math3-3.6.1.jar"); - File buildDir = new File("my-project/build/classes/java/main"); - JcDatabase database = JacoDB.async( - new JcSettings() - .useProcessJavaRuntime() - .persistent("/tmp/compilation-db/" + System.currentTimeMillis()) // persist data - ).get(); - - // Let's load these three bytecode locations - database.asyncLoad(Arrays.asList(commonsMath32, commonsMath36, buildDir)); - - // This method just refreshes the libraries inside the database. If there are any changes in libs then - // the database updates data with the new results. - database.asyncLoad(singletonList(buildDir)); - - // Let's assume that we want to get bytecode info only for `commons-math3` version 3.2. - JcClassOrInterface jcClass = database.asyncClasspath(Arrays.asList(commonsMath32, buildDir)) - .get().findClassOrNull("org.apache.commons.math3.distribution.NormalDistribution"); - System.out.println(jcClass.getDeclaredMethods().size()); - System.out.println(jcClass.getAnnotations().size()); - System.out.println(JcClasses.getConstructors(jcClass).size()); - - // At this point the database read the method bytecode and return the result. - return jcClass.getDeclaredMethods().get(0).withAsmNode(it -> it); - } - - public static void watchFileChanges() throws Exception { - JcDatabase database = JacoDB.async(new JcSettings() - .watchFileSystem() - .useProcessJavaRuntime() - .loadByteCode(Arrays.asList(lib1, buildDir)) - .persistent("", false)).get(); - } - - public static class A { - T x = null; - } - - public static class B extends A { - } - - public static void typesSubstitution() { - JcClassType b = (JcClassType) classpath.findTypeOrNull("org.jacodb.examples.JavaReadMeExamples.B"); - JcType xType = b.getFields() - .stream() - .filter(it -> "x".equals(it.getName())) - .findFirst().get().getType(); - JcClassType stringType = (JcClassType) classpath.findTypeOrNull("java.lang.String"); - System.out.println(xType.equals(stringType)); // will print `true` - } - - public static void refresh() throws Exception { - JcDatabase database = JacoDB.async( - new JcSettings() - .watchFileSystem() - .useProcessJavaRuntime() - .loadByteCode(Arrays.asList(lib1, buildDir)) - .persistent("...") - ).get(); - - JcClasspath cp = database.asyncClasspath(singletonList(buildDir)).get(); - database.asyncRefresh().get(); // does not affect cp classes - - JcClasspath cp1 = database.asyncClasspath(singletonList(buildDir)).get(); // will use new version of compiled results in buildDir - } - - public static void autoProcessing() throws Exception { - JcDatabase database = JacoDB.async( - new JcSettings() - .loadByteCode(Arrays.asList(lib1)) - .persistent("...") - ).get(); - - JcClasspath cp = database.asyncClasspath(singletonList(buildDir)).get(); // database will automatically process buildDir - } - - public static void threadSafe() throws Exception { - JcDatabase db = JacoDB.async(new JcSettings()).get(); - - new Thread(() -> { - try { - db.asyncLoad(Arrays.asList(lib1, lib2)).get(); - } catch (Exception e) { - // should never happen - } - }).start(); - - new Thread(() -> { - // maybe created when lib2 or both are not loaded into database - // but buildDir will be loaded anyway - try { - JcClasspath cp = db.asyncClasspath(singletonList(buildDir)).get(); - } catch (Exception e) { - // should never happen - } - }).start(); - } -} diff --git a/jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt b/jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt deleted file mode 100644 index 056b52ccf..000000000 --- a/jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.examples - -import kotlinx.coroutines.runBlocking -import org.jacodb.api.jvm.ext.constructors -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.api.jvm.ext.toType -import org.jacodb.impl.jacodb -import java.io.File -import kotlin.concurrent.thread - -val lib1 = File("1") -val lib2 = File("2") -val buildDir = File("3") - - -suspend fun findNormalDistribution(): Any { - val commonsMath32 = File("commons-math3-3.2.jar") - val commonsMath36 = File("commons-math3-3.6.1.jar") - val buildDir = File("my-project/build/classes/java/main") - val database = jacodb { - useProcessJavaRuntime() - persistent("/tmp/compilation-db/${System.currentTimeMillis()}") // persist data - } - - // Let's load these three bytecode locations - database.load(listOf(commonsMath32, commonsMath36, buildDir)) - - // This method just refreshes the libraries inside the database. If there are any changes in libs then - // the database updates data with the new results. - database.load(listOf(buildDir)) - - // Let's assume that we want to get bytecode info only for `commons-math3` version 3.2. - val jcClass = database.classpath(listOf(commonsMath32, buildDir)) - .findClass("org.apache.commons.math3.distribution.NormalDistribution") - println(jcClass.declaredMethods.size) - println(jcClass.constructors.size) - println(jcClass.annotations.size) - - // At this point the database read the method bytecode and return the result. - return jcClass.methods[0].withAsmNode { it } -} - -suspend fun watchFileChanges() { - val database = jacodb { - watchFileSystem() - useProcessJavaRuntime() - loadByteCode(listOf(lib1, buildDir)) - persistent("") - } -} - -open class A(val x: T) - -class B(x: String) : A(x) - -suspend fun typesSubstitution() { - val db = jacodb { - loadByteCode(listOf(File("all-classpath"))) - } - val classpath = db.classpath(listOf(File("all-classpath"))) - val b = classpath.findClass().toType() - println(b.fields.first { it.name == "x" }.type == classpath.findClass().toType()) // will print `true` -} - -suspend fun refresh() { - val database = jacodb { - watchFileSystem() - useProcessJavaRuntime() - loadByteCode(listOf(lib1, buildDir)) - persistent("") - } - - val cp = database.classpath(listOf(buildDir)) - database.refresh() // does not affect cp classes - - val cp1 = database.classpath(listOf(buildDir)) // will use new version of compiled results in buildDir -} - -suspend fun autoLoad() { - val database = jacodb { - loadByteCode(listOf(lib1)) - persistent("") - } - - val cp = database.classpath(listOf(buildDir)) // database will automatically process buildDir -} - - -suspend fun threadSafe() { - val db = jacodb { - persistent("") - } - - thread(start = true) { - runBlocking { - db.load(listOf(lib1, lib2)) - } - } - - thread(start = true) { - runBlocking { - // maybe created when lib2 or both are not loaded into database - // but buildDir will be loaded anyway - val cp = db.classpath(listOf(buildDir)) - } - } - -} diff --git a/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt b/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt deleted file mode 100644 index a9112777b..000000000 --- a/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.examples.analysis - -import kotlinx.coroutines.runBlocking -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcClassProcessingTask -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.RegisteredLocation -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.hasAnnotation -import org.jacodb.impl.fs.BuildFolderLocation -import org.jacodb.impl.jacodb -import soot.SootMethod -import soot.jimple.Stmt -import soot.tagkit.LineNumberTag -import java.io.File -import java.util.concurrent.ConcurrentHashMap -import kotlin.system.measureTimeMillis - - -data class User(val login: String) - -annotation class HighPerformance -annotation class Slow - -class Service { - private val cache = ConcurrentHashMap() - - @Slow - fun recalculateIndexes() { - Thread.sleep(10_000) - } - - fun admin() = cache.getOrPut("admin") { - recalculateIndexes() - User("admin") - } - -} - -class Controller(private val service: Service) { - - @HighPerformance - fun getAdminUser() { - val user = service.admin() - println("admin is $user") - } -} - -private val JcInst.ref: String - get() { - val method = location.method - val sourceFile = method.enclosingClass.withAsmNode { it.sourceFile } - return "${method.enclosingClass.name}.${method.name}($sourceFile:${location.lineNumber})" - } - -private fun SootMethod.ref(stmt: Stmt): String { - return "${declaringClass.name}.${name}:${stmt.lineNumber})" -} - -private val Stmt.lineNumber: String - get() { - return tags.filterIsInstance().firstOrNull()?.lineNumber?.toString() ?: "unknown" - } - - -interface MaybePath - -object NoPath : MaybePath - -class AccessPath(private val list: List) : MaybePath { - - constructor(inst: JcInst) : this(listOf(inst.ref)) - constructor(method: SootMethod, stmt: Stmt) : this(listOf(method.ref(stmt))) - - fun add(inst: JcInst): AccessPath { - return join(AccessPath(inst)) - } - - fun join(another: AccessPath): AccessPath { - return AccessPath(list + another.list) - } - - fun join(another: JcInst): AccessPath { - return AccessPath(list + another.ref) - } - - fun join(method: SootMethod, stmt: Stmt): AccessPath { - return AccessPath(list + method.ref(stmt)) - } - - override fun toString(): String { - return buildString { - append("Performance issue found:") - list.forEach { - appendLine() - append("\t") - append(it) - } - } - } -} - -internal val highPerformance = HighPerformance::class.java.name -internal val slow = Slow::class.java.name - -class HighPerformanceChecker : JcClassProcessingTask { - - private val slowCallCache = ConcurrentHashMap() - - override fun shouldProcess(registeredLocation: RegisteredLocation): Boolean { - return registeredLocation.jcLocation is BuildFolderLocation - } - - override fun process(clazz: JcClassOrInterface) { - clazz.declaredMethods - .filter { it.hasAnnotation(highPerformance) } - .forEach { - val path = it.isSlowCallPath(slowCallCache) - if (path is AccessPath) { - println(path) - } - } - } - - private val JcClassOrInterface.isSystem: Boolean - get() { - return name.startsWith("java") || name.startsWith("kotlin") - } - - private fun JcMethod.isSlowCallPath( - cache: ConcurrentHashMap, - processingMethods: Set = hashSetOf(this) - ): MaybePath { - return cache.getOrPut(this) { - isSlowCallPath(processingMethods) - } - } - - private fun JcMethod.isSlowCallPath(methods: Set = hashSetOf(this)): MaybePath { - for (inst in instList) { - val method = inst.callExpr?.method?.method ?: continue - if (!methods.contains(method) && !method.enclosingClass.isSystem) { - if (method.hasAnnotation(slow)) { - return AccessPath(inst) - } else if (method.isAbstract) { - return NoPath - } - val callPath = method.isSlowCallPath(slowCallCache, methods + method) - if (callPath is AccessPath) { - return callPath.join(inst) - } - } - } - return NoPath - } -} - -val allClasspath: List - get() { - return classpath.map { File(it) } - } - -private val classpath: List - get() { - val classpath = System.getProperty("java.class.path") - return classpath.split(File.pathSeparatorChar).toList() - } - -fun main() { - println("JacoDB tooks: " + measureTimeMillis { - runBlocking { - val db = jacodb { - loadByteCode(allClasspath) - } - val cp = db.classpath(allClasspath) - val checker = HighPerformanceChecker() - cp.execute(checker) - } - } + "ms to finish") - -} diff --git a/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt b/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt deleted file mode 100644 index d47764ce6..000000000 --- a/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.examples.analysis - -import org.jacodb.api.jvm.ext.jvmName -import soot.G -import soot.Scene -import soot.SootClass -import soot.SootMethod -import soot.jimple.Stmt -import soot.options.Options -import soot.tagkit.VisibilityAnnotationTag -import java.io.File -import java.util.concurrent.ConcurrentHashMap -import kotlin.system.measureTimeMillis - -fun initSoot(files: List) { - G.reset() - val options = Options.v() - val version = 11 - val location = System.getProperty("java.home") - - G.v().initJdk(G.JreInfo(location, version)) // init Soot with the right jdk - options.apply { - set_prepend_classpath(true) - // set true to debug. Disabled because of a bug when two different variables - // from the source code have the same name in the jimple body. - setPhaseOption("jb", "use-original-names:false") - set_soot_classpath(files.filter { it.exists() }.joinToString(File.pathSeparator) { it.absolutePath }) - set_process_dir(files.filter { it.exists() }.map { it.absolutePath }) - - set_src_prec(Options.src_prec_only_class) - set_keep_line_number(true) - set_ignore_classpath_errors(true) // gradle/build/resources/main does not exists, but it's not a problem - set_output_format(Options.output_format_jimple) - /** - * In case of Java8, set_full_resolver(true) fails with "soot.SootResolver$SootClassNotFoundException: - * couldn't find class: javax.crypto.BadPaddingException (is your soot-class-path set properly?)". - * To cover that, set_allow_phantom_refs(true) is required - */ - set_allow_phantom_refs(true) // Java8 related - set_full_resolver(true) - set_whole_program(true) - } - Scene.v().loadNecessaryClasses() -} - -private val highPerformanceJvm = highPerformance.jvmName() -private val slowJvm = slow.jvmName() - -class SootHighPerformanceChecker { - - private val slowCallCache = ConcurrentHashMap() - - fun process(clazz: SootClass) { - clazz.methods - .filter { it.hasAnnotation(highPerformanceJvm) } - .forEach { - val path = it.isSlowCallPath(slowCallCache) - if (path is AccessPath) { - println(path) - } - } - } - - private val SootClass.isSystem: Boolean - get() { - return packageName.startsWith("java") || packageName.startsWith("kotlin") - } - - private fun SootMethod.hasAnnotation(name: String): Boolean { - return tags.any { it is VisibilityAnnotationTag && it.annotations.any { it.type == name } } - } - - private fun SootMethod.isSlowCallPath( - cache: ConcurrentHashMap, - processingMethods: Set = hashSetOf(this) - ): MaybePath { - return cache.getOrPut(this) { - isSlowCallPath(processingMethods) - } - } - - private fun SootMethod.isSlowCallPath(methods: Set = hashSetOf(this)): MaybePath { - for (stmt in retrieveActiveBody().units.filterIsInstance()) { - if (!stmt.containsInvokeExpr()) { - continue - } - val method = stmt.invokeExpr.method ?: continue - if (!methods.contains(method) && !method.declaringClass.isSystem) { - if (method.hasAnnotation(slowJvm)) { - return AccessPath(method, stmt) - } else if (method.isAbstract) { - return NoPath - } - val callPath = method.isSlowCallPath(slowCallCache, methods + method) - if (callPath is AccessPath) { - return callPath.join(method, stmt) - } - } - } - return NoPath - } -} - -fun main() { - println("Soot tooks: " + measureTimeMillis { - initSoot(allClasspath) - val checker = SootHighPerformanceChecker() - Scene.v().applicationClasses - .filter { it.packageName == "org.jacodb.examples.analysis" } - .stream() - .parallel() - .forEach { checker.process(it) } - } + "ms to finish") -} diff --git a/jacodb-panda-static/build.gradle.kts b/jacodb-panda-static/build.gradle.kts deleted file mode 100644 index 65a2830e3..000000000 --- a/jacodb-panda-static/build.gradle.kts +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - kotlin("plugin.serialization") -} - -repositories { - mavenCentral() -} - -dependencies { - api(project(":jacodb-core")) - api(project(":jacodb-api-common")) - - implementation(Libs.kotlin_logging) - implementation(Libs.slf4j_simple) - implementation(Libs.kotlinx_serialization_json) - implementation(Libs.jdot) - - testImplementation(kotlin("test")) - testImplementation(project(":jacodb-analysis")) - testImplementation(testFixtures(project(":jacodb-core"))) - testImplementation(Libs.mockk) -} - -tasks.test { - useJUnitPlatform() -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt deleted file mode 100644 index 51c406e5b..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.BytecodeGraph -import org.jacodb.api.common.cfg.Graph -import org.jacodb.panda.staticvm.* -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.utils.OneDirectionGraph - -interface PandaBytecodeGraph : BytecodeGraph - -/** - * Control flow graph for a single [PandaMethod]. - */ -class PandaGraph private constructor( - private val instList: PandaInstList, - private val graph: OneDirectionGraph, - private val throwGraph: OneDirectionGraph, -) : PandaBytecodeGraph, Graph { - - override val entries: List = listOfNotNull(instList.firstOrNull()) - - override val exits: List = setOfNotNull(instList.lastOrNull().takeIf { it !is PandaGotoInst }) - .plus(instList.filterIsInstance()) - .toList() - - override val instructions: List = instList.instructions - - fun index(inst: PandaInst): Int { - if (inst in instructions) { - return inst.location.index - } - return -1 - } - - fun ref(inst: PandaInst): PandaInstRef = PandaInstRef(index(inst)) - fun inst(ref: PandaInstRef): PandaInst = instructions[ref.index] - - fun previous(inst: PandaInst): PandaInst = instructions[ref(inst).index - 1] - fun next(inst: PandaInst): PandaInst = instructions[ref(inst).index + 1] - - override fun successors(node: PandaInst): Set = graph.successors(node) - override fun predecessors(node: PandaInst): Set = graph.predecessors(node) - - override fun throwers(node: PandaInst): Set = throwGraph.predecessors(node) - override fun catchers(node: PandaInst): Set = throwGraph.successors(node) - - companion object { - fun empty(): PandaGraph { - return PandaGraph( - PandaInstList(emptyList()), - OneDirectionGraph(emptySet()) { emptySet() }, - OneDirectionGraph(emptySet()) { emptySet() } - ) - } - - fun of(method: PandaMethod, blocks: List): PandaGraph { - val instListBuilder = InstListBuilder(method, blocks) - val instList = instListBuilder.instList - val graph = OneDirectionGraph(instList) { inst -> - when (inst) { - is PandaBranchingInst -> inst.successors.map { instList[it.index] } - is PandaTerminatingInst -> emptyList() - else -> listOfNotNull(instList.getOrNull(instList.indexOf(inst) + 1)) - } - } - val throwGraph = OneDirectionGraph(instList) { thrower -> - instListBuilder.throwEdges - .filter { (from, _) -> instList[from.index] == thrower } - .map { instList[it.second.index] } - } - // instListBuilder.throwEdges.applyFold(graph) { (from, to) -> withEdge(instList[from.index], instList[to.index]) } - return PandaGraph(PandaInstList(instList), graph, throwGraph) - } - } -} - -class PandaApplicationGraph( - val cp: PandaProject, -) : ApplicationGraph { - private val callersMap = cp.methods - .flatMap { it.flowGraph().instructions } - .flatMap { inst -> callees(inst).map { it to inst } } - .groupBy(Pair::first, Pair::second) - - override fun predecessors(node: PandaInst): Sequence { - val graph = node.location.method.flowGraph() - val predecessors = graph.predecessors(node) - if (node is PandaCatchInst) { - val throwers = graph.throwers(node) - return predecessors.asSequence() + throwers.asSequence() - } else { - return predecessors.asSequence() - } - } - - override fun successors(node: PandaInst): Sequence { - val graph = node.location.method.flowGraph() - val successors = graph.successors(node) - if (node is PandaThrowInst) { - val catchers = graph.catchers(node) - return successors.asSequence() + catchers.asSequence() - } else { - return successors.asSequence() - } - } - - override fun callees(node: PandaInst): Sequence = when (node) { - is PandaAssignInst -> when (val expr = node.rhv) { - is PandaStaticCallExpr -> sequenceOf(expr.method) - is PandaVirtualCallExpr -> sequenceOf(expr.method) - else -> emptySequence() - } - - else -> emptySequence() - } - - override fun callers(method: PandaMethod): Sequence { - return callersMap[method]?.asSequence() ?: emptySequence() - } - - override fun entryPoints(method: PandaMethod): Sequence { - return method.flowGraph().entries.asSequence() - } - - override fun exitPoints(method: PandaMethod): Sequence { - return method.flowGraph().exits.asSequence() - } - - override fun methodOf(node: PandaInst): PandaMethod { - return node.location.method - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt deleted file mode 100644 index 4dc460436..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -import info.leadinglight.jdot.Edge -import info.leadinglight.jdot.Graph -import info.leadinglight.jdot.Node -import info.leadinglight.jdot.enums.Color -import info.leadinglight.jdot.enums.Shape -import info.leadinglight.jdot.enums.Style -import info.leadinglight.jdot.impl.Util -import org.jacodb.impl.cfg.graphs.GraphDominators -import java.io.File -import java.nio.file.Files -import java.nio.file.Path - -fun PandaGraph.view(dotCmd: String, viewerCmd: String, viewCatchConnections: Boolean = false) { - Util.sh(arrayOf(viewerCmd, "file://${toFile(dotCmd, viewCatchConnections)}")) -} - -fun PandaGraph.toFile(dotCmd: String, viewCatchConnections: Boolean = false, file: File? = null): Path { - Graph.setDefaultCmd(dotCmd) - - val graph = Graph("pandaGraph") - - val nodes = mutableMapOf() - for ((index, inst) in instructions.withIndex()) { - val node = Node("$index") - .setShape(Shape.box) - .setLabel(inst.toString().replace("\"", "\\\"")) - .setFontSize(12.0) - nodes[inst] = node - graph.addNode(node) - } - - graph.setBgColor(Color.X11.transparent) - graph.setFontSize(12.0) - graph.setFontName("Fira Mono") - - for ((inst, node) in nodes) { - when (inst) { - is PandaGotoInst -> for (successor in successors(inst)) { - graph.addEdge(Edge(node.name, nodes[successor]!!.name)) - } - - is PandaIfInst -> { - graph.addEdge( - Edge(node.name, nodes[inst(inst.trueBranch)]!!.name) - .also { - it.setLabel("true") - } - ) - graph.addEdge( - Edge(node.name, nodes[inst(inst.falseBranch)]!!.name) - .also { - it.setLabel("false") - } - ) - } - - // is PandaSwitchInst -> { - // for ((key, branch) in inst.branches) { - // graph.addEdge( - // Edge(node.name, nodes[inst(branch)]!!.name) - // .also { - // it.setLabel("$key") - // } - // ) - // } - // graph.addEdge( - // Edge(node.name, nodes[inst(inst.default)]!!.name) - // .also { - // it.setLabel("else") - // } - // ) - // } - - else -> for (successor in successors(inst)) { - graph.addEdge(Edge(node.name, nodes[successor]!!.name)) - } - } - if (viewCatchConnections) { - for (catcher in catchers(inst)) { - graph.addEdge(Edge(node.name, nodes[catcher]!!.name).also { - // it.setLabel("catch ${catcher.throwable.type}") - it.setLabel("catch") - it.setStyle(Style.Edge.dashed) - }) - } - } - } - - val outFile = graph.dot2file("svg") - val newFile = "${outFile.removeSuffix(".out")}.svg" - val resultingFile = file?.toPath() ?: File(newFile).toPath() - Files.move(File(outFile).toPath(), resultingFile) - return resultingFile -} - -fun PandaGraph.findDominators(): GraphDominators { - return GraphDominators(this).also { - it.find() - } -} - -// fun PandaBlockGraph.findDominators(): GraphDominators { -// return GraphDominators(this).also { -// it.find() -// } -// } diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt deleted file mode 100644 index 52873dd62..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt +++ /dev/null @@ -1,857 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("MemberVisibilityCanBePrivate") - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.panda.staticvm.classpath.PandaArrayType -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaPrimitiveType -import org.jacodb.panda.staticvm.classpath.PandaPrimitives -import org.jacodb.panda.staticvm.classpath.PandaType -import org.jacodb.panda.staticvm.ir.PandaAShlInstIr -import org.jacodb.panda.staticvm.ir.PandaAShrInstIr -import org.jacodb.panda.staticvm.ir.PandaAddInstIr -import org.jacodb.panda.staticvm.ir.PandaAndInstIr -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.ir.PandaBitcastInstIr -import org.jacodb.panda.staticvm.ir.PandaBoundsCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaBuiltinInstIr -import org.jacodb.panda.staticvm.ir.PandaCallDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCatchPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaCheckCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCmpInstIr -import org.jacodb.panda.staticvm.ir.PandaCompareInstIr -import org.jacodb.panda.staticvm.ir.PandaConstantInstIr -import org.jacodb.panda.staticvm.ir.PandaDivInstIr -import org.jacodb.panda.staticvm.ir.PandaFillConstArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaFunctionImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaHclassCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaIfImmInstIr -import org.jacodb.panda.staticvm.ir.PandaInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIrVisitor -import org.jacodb.panda.staticvm.ir.PandaIntrinsicInstIr -import org.jacodb.panda.staticvm.ir.PandaIsInstanceInstIr -import org.jacodb.panda.staticvm.ir.PandaLenArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadAndInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadFromConstantPoolInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjFromConstInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadRuntimeClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStringInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadTypeInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadUndefinedInstIr -import org.jacodb.panda.staticvm.ir.PandaModInstIr -import org.jacodb.panda.staticvm.ir.PandaMulInstIr -import org.jacodb.panda.staticvm.ir.PandaNegInstIr -import org.jacodb.panda.staticvm.ir.PandaNegativeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNewArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaNewObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaNotInstIr -import org.jacodb.panda.staticvm.ir.PandaNullCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNullPtrInstIr -import org.jacodb.panda.staticvm.ir.PandaOrInstIr -import org.jacodb.panda.staticvm.ir.PandaParameterInstIr -import org.jacodb.panda.staticvm.ir.PandaPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaRefTypeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnVoidInstIr -import org.jacodb.panda.staticvm.ir.PandaSafePointInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateDeoptimizeInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateInstIr -import org.jacodb.panda.staticvm.ir.PandaShlInstIr -import org.jacodb.panda.staticvm.ir.PandaShrInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaSubInstIr -import org.jacodb.panda.staticvm.ir.PandaTerminatingInstIr -import org.jacodb.panda.staticvm.ir.PandaThrowInstIr -import org.jacodb.panda.staticvm.ir.PandaTryInstIr -import org.jacodb.panda.staticvm.ir.PandaXorInstIr -import org.jacodb.panda.staticvm.ir.PandaZeroCheckInstIr -import org.jacodb.panda.staticvm.utils.OneDirectionGraph -import org.jacodb.panda.staticvm.utils.SCCs -import org.jacodb.panda.staticvm.utils.inTopsortOrder -import org.jacodb.panda.staticvm.utils.runDP -import java.nio.ByteBuffer -import java.nio.ByteOrder -import kotlin.reflect.typeOf - -fun interface InstBuilder { - fun build(): PandaInst -} - -fun interface ThrowInstBuilder : InstBuilder { - override fun build(): PandaThrowInst -} - -data class IrInstLocation(val block: Int, val index: Int) - -class InstListBuilder( - val method: PandaMethod, - val blocks: List, -) { - val project = method.enclosingClass.project - - private val localVars = buildLocalVariables(method, blocks) - private val locationMap = hashMapOf() - private val blockIdMap = blocks.mapIndexed { index, block -> block.id to index }.toMap() - - private fun getBlock(id: Int): PandaBasicBlockIr = blocks[requireNotNull(blockIdMap[id])] - - private fun linearRef(location: IrInstLocation): PandaInstRef { - val loc = locationMap[location] - ?: error("No location $location for method: $method") - return PandaInstRef(loc) - } - - fun local(name: String): PandaLocalVar = localVars[name] - ?: error("No local $name for method: $method") - - fun result(inst: PandaInstIr): PandaLocalVar = local(inst.id) - - private val instBuilders: MutableList = mutableListOf() - - private inline fun push(noinline build: (PandaInstLocation) -> T) { - val index = instBuilders.size - when (typeOf()) { - typeOf() -> { - @Suppress("UNCHECKED_CAST", "NAME_SHADOWING") - val build = build as (PandaInstLocation) -> PandaThrowInst - instBuilders += ThrowInstBuilder { build(PandaInstLocation(method, index)) } - } - - else -> { - instBuilders += InstBuilder { build(PandaInstLocation(method, index)) } - } - } - } - - internal fun pushAssign(lhv: PandaValue, rhv: PandaExpr) { - push { location -> - PandaAssignInst(location, lhv, rhv) - } - } - - internal fun pushParameter(lhv: PandaValue, index: Int) { - push { location -> - PandaParameterInst(location, lhv, index) - } - } - - internal fun pushReturn(value: PandaValue?) { - push { location -> - PandaReturnInst( - location = location, - returnValue = value - ) - } - } - - internal fun pushIf( - conditionExpr: PandaConditionExpr, - trueBranch: IrInstLocation, - falseBranch: IrInstLocation, - ) { - push { location -> - PandaIfInst( - location = location, - condition = conditionExpr, - trueBranch = linearRef(trueBranch), - falseBranch = linearRef(falseBranch) - ) - } - } - - internal fun pushGoto(target: IrInstLocation) { - push { location -> - PandaGotoInst( - location = location, - target = linearRef(target) - ) - } - } - - internal fun pushDoNothing() { - push { location -> - PandaDoNothingInst(location) - } - } - - internal fun pushCatchPhi( - lhv: PandaValue, - inputs: List, - throwers: List, - ) { - push { location -> - val throwerIndices = throwers.map { idMap[it] }.requireNoNulls() - - val (throwInputs, throwPredecessors) = (inputs zip throwerIndices).filter { (_, thrower) -> - instBuilders[thrower] is ThrowInstBuilder - }.unzip() - val predecessors = throwPredecessors.map { PandaInstRef(it) } - PandaPhiInst( - location = location, - lhv = lhv, - phiInputs = throwInputs.zip(predecessors, PandaPhiInst::PhiInput) - ) - } - } - - internal fun pushPhi( - lhv: PandaValue, - inputs: List, - blocks: List, - ) { - push { location -> - val predecessors = blocks.map { - linearRef(IrInstLocation(it, maxOf(0, getBlock(it).insts.lastIndex))) - } - PandaAssignInst( - location, lhv, PandaPhiExpr(lhv.type, inputs, predecessors) - ) - /*PandaPhiInst( - location = location, - lhv = lhv, - phiInputs = inputs.zip(predecessors, PandaPhiInst::PhiInput) - )*/ - } - } - - internal fun pushCatch(lhv: PandaValue, throwerIds: List) = push { location -> - PandaCatchInst(location, lhv, TODO()) - } - - internal fun pushThrow(error: PandaValue, catchers: List) { - push { location -> - PandaThrowInst( - location = location, - error = error, - catchers = catchers.map { linearRef(IrInstLocation(it, 0)) } - ) - } - } - - private val idMap: MutableMap = hashMapOf() - - private val throwEdgeBuilders: MutableList> = mutableListOf() - - private val throwersToCatchBlocks = OneDirectionGraph(blocks) { block -> - block.insts.flatMap { it.catchers }.map(this::getBlock) - } - - private fun throwersLocations(block: PandaBasicBlockIr) = - block.insts.mapIndexedNotNull { index, inst -> - if (inst.catchers.isNotEmpty()) IrInstLocation(block.id, index) else null - } - - init { - val visitor = InstListBuilderVisitor() - blocks.sortedBy { it.predecessors.size }.forEach { block -> - if (block.isCatchBegin) { - visitor.location = IrInstLocation(block.id, 0) - locationMap[visitor.location] = instBuilders.size - val exceptionCatcher = block.insts - .filterIsInstance() - .find { it.throwers.isEmpty() } - exceptionCatcher?.let { - push { location -> - PandaCatchInst( - location, - result(it), - throwersToCatchBlocks - .predecessors(block) - .flatMap { throwersLocations(it) } - .map(this::linearRef) - ) - } - } - } - - if (block.isTryBegin) { - visitor.location = IrInstLocation(block.id, 0) - locationMap[visitor.location] = instBuilders.size - push { location -> - PandaTryPseudoInst(location, block.successors.drop(1).map { linearRef(IrInstLocation(it, 0)) }) - } - } - - block.insts.forEachIndexed { instIndex, inst -> - visitor.location = IrInstLocation(block.id, instIndex) - locationMap.putIfAbsent(visitor.location, instBuilders.size) - idMap[inst.id] = instBuilders.size - - inst.accept(visitor) - - if (inst is PandaThrowInstIr) { - throwEdgeBuilders.addAll(inst.catchers.map { visitor.location to IrInstLocation(it, 0) }) - } - } - - val endOfBlock = IrInstLocation(block.id, block.insts.size) - visitor.location = endOfBlock - locationMap[endOfBlock] = instBuilders.size - if (block.isTryBegin || block.isTryEnd) { - pushGoto(IrInstLocation(block.successors.first(), 0)) - } else { - block.successors.singleOrNull()?.let { - if (block.insts.lastOrNull() !is PandaTerminatingInstIr) { - pushGoto(IrInstLocation(it, 0)) - } - } ?: if (block.insts.isEmpty()) { - pushDoNothing() - } else Unit - } - } - } - - val instList: List = instBuilders.map { it.build() } - - val throwEdges: List> = throwEdgeBuilders.map { (from, to) -> - linearRef(from) to linearRef(to) - } -} - -internal fun buildLocalVariables( - pandaMethod: PandaMethod, - blocks: List, -): Map { - val project = pandaMethod.enclosingClass.project - - val localVarsIndex = hashMapOf() - - val handledType = blocks.flatMap { it.handlers }.associate { - val t = if (it.type == "finally") null else it.type - it.id to t?.let { n -> project.findTypeOrNull(n) } - } - - val varNodes = blocks.flatMap { block -> - val outputVarBuilder = OutputVarBuilder(pandaMethod, block, handledType[block.id]) - block.insts.mapNotNull { it.accept(outputVarBuilder) } - }.associateBy { it.name } - - val graph = OneDirectionGraph(varNodes.values) { node -> - when (node) { - is LeafVarNode -> emptySet() - is DependentVarNode -> node.bounds.mapTo(hashSetOf()) { requireNotNull(varNodes[it]) } - is LoadArrayNode -> setOf(requireNotNull(varNodes[node.array])) - } - } - - val sccs = graph.SCCs() - check(sccs.inTopsortOrder() != null) - - graph.SCCs().runDP { vars, inputTypes -> - vars.map { lv -> - when (lv) { - is LeafVarNode -> lv.type - - is DependentVarNode -> project.commonType(inputTypes.values.flatten()) - ?: error("No common type for ${inputTypes.values}") - - is LoadArrayNode -> { - val arrayTypes = inputTypes.values.flatten() - require(arrayTypes.all { it is PandaArrayType || it == project.objectClass.type }) { - println() - } - val elementTypes = arrayTypes.filterIsInstance().map { it.elementType } - requireNotNull(project.commonType(elementTypes)) - } - }.also { - if (lv is ThisNode) { - localVarsIndex[lv.name] = PandaThis(lv.name, it) - } else { - localVarsIndex[lv.name] = PandaLocalVarImpl(lv.name, it) - } - } - } - } - - return localVarsIndex -} - -context(InstListBuilder) -class InstListBuilderVisitor : PandaInstIrVisitor { - lateinit var location: IrInstLocation - - private inline fun convert(value: ULong, getter: ByteBuffer.() -> T) = ByteBuffer - .allocate(16) - .order(ByteOrder.LITTLE_ENDIAN) - .putLong(value.toLong()) - .rewind() - .let { it as ByteBuffer } - .let(getter) - - private fun getConstant(value: ULong, type: PandaPrimitiveType) = when (type) { - PandaPrimitiveType.VOID -> throw IllegalArgumentException("cannot create void constant") - PandaPrimitiveType.NULL -> PandaNull - PandaPrimitiveType.BOOL -> PandaBoolean(value != 0UL) - PandaPrimitiveType.BYTE -> PandaByte(value.toByte()) - PandaPrimitiveType.UBYTE -> PandaUByte(value.toUByte()) - PandaPrimitiveType.SHORT -> PandaShort(value.toShort()) - PandaPrimitiveType.USHORT -> PandaUShort(value.toUShort()) - PandaPrimitiveType.INT -> PandaInt(value.toInt()) - PandaPrimitiveType.UINT -> PandaUInt(value.toUInt()) - PandaPrimitiveType.LONG -> PandaLong(value.toLong()) - PandaPrimitiveType.ULONG -> PandaULong(value) - PandaPrimitiveType.FLOAT -> PandaFloat(convert(value, ByteBuffer::getFloat)) - PandaPrimitiveType.DOUBLE -> PandaDouble(convert(value, ByteBuffer::getDouble)) - } - - private fun getConditionType(operator: String) = when (operator) { - "LE" -> ::PandaLeExpr - "LT" -> ::PandaLtExpr - "GE" -> ::PandaGeExpr - "GT" -> ::PandaGtExpr - "EQ" -> ::PandaEqExpr - "NE" -> ::PandaNeExpr - else -> throw AssertionError("Unknown operator: $operator") - } - - private fun skip() {} - - private fun pushUnary( - inst: PandaInstIr, - exprConstructor: (PandaType, PandaValue) -> PandaUnaryExpr, - ) { - val type = project.findType(inst.type) - val value = local(inst.inputs[0]) - val expr = exprConstructor(type, value) - pushAssign(result(inst), expr) - } - - private fun pushBinary( - inst: PandaInstIr, - exprConstructor: (PandaType, PandaValue, PandaValue) -> PandaBinaryExpr, - ) { - val type = project.findType(inst.type) - val (lhv, rhv) = inst.inputs.map { local(it) } - val expr = exprConstructor(type, lhv, rhv) - pushAssign(result(inst), expr) - } - - override fun visitPandaConstantInstIr(inst: PandaConstantInstIr) { - val constant = getConstant(inst.value, PandaPrimitives.find(inst.type)) - pushAssign(result(inst), constant) - } - - override fun visitPandaSafePointInstIr(inst: PandaSafePointInstIr) { - skip() - } - - override fun visitPandaSaveStateInstIr(inst: PandaSaveStateInstIr) { - skip() - } - - override fun visitPandaNewObjectInstIr(inst: PandaNewObjectInstIr) { - val type = project.findClass(inst.objectClass).type - val newExpr = PandaNewExpr(type) - pushAssign(result(inst), newExpr) - } - - override fun visitPandaNewArrayInstIr(inst: PandaNewArrayInstIr) { - val type = project.getElementType(inst.arrayType) - val length = local(inst.inputs[1]) - val newArrayExpr = PandaNewArrayExpr(type, length) - pushAssign(result(inst), newArrayExpr) - } - - override fun visitPandaCallStaticInstIr(inst: PandaCallStaticInstIr) { - val callee = project.findMethod(inst.method) - val args = inst.inputs.take(callee.parameterTypes.size).map { local(it) } - val callExpr = PandaStaticCallExpr(callee, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaCallLaunchStaticInstIr(inst: PandaCallLaunchStaticInstIr) { - val callee = project.findMethod(inst.method) - val args = inst.inputs.take(callee.parameterTypes.size).map { local(it) } - val callExpr = PandaStaticCallExpr(callee, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaNullCheckInstIr(inst: PandaNullCheckInstIr) { - pushAssign(result(inst), local(inst.inputs.first())) - } - - override fun visitPandaZeroCheckInstIr(inst: PandaZeroCheckInstIr) { - pushAssign(result(inst), local(inst.inputs.first())) - } - - override fun visitPandaLoadStringInstIr(inst: PandaLoadStringInstIr) { - pushAssign(result(inst), PandaString(inst.string, project.stringClass.type)) - } - - override fun visitPandaCallVirtualInstIr(inst: PandaCallVirtualInstIr) { - val callee = project.findMethod(inst.method) - val instance = local(inst.inputs[0]) - val args = inst.inputs.drop(1).take(callee.parameterTypes.size - 1).map { local(it) } - val callExpr = PandaVirtualCallExpr(callee, instance, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaCallLaunchVirtualInstIr(inst: PandaCallLaunchVirtualInstIr) { - val callee = project.findMethod(inst.method) - val instance = local(inst.inputs[0]) - val args = inst.inputs.drop(1).take(callee.parameterTypes.size - 1).map { local(it) } - val callExpr = PandaVirtualCallExpr(callee, instance, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaLoadAndInitClassInstIr(inst: PandaLoadAndInitClassInstIr) { - skip() - } - - override fun visitPandaLoadClassInstIr(inst: PandaLoadClassInstIr) { - skip() - } - - override fun visitPandaInitClassInstIr(inst: PandaInitClassInstIr) { - skip() - } - - override fun visitPandaReturnVoidInstIr(inst: PandaReturnVoidInstIr) { - pushReturn(null) - } - - override fun visitPandaReturnInstIr(inst: PandaReturnInstIr) { - pushReturn(local(inst.inputs[0])) - } - - override fun visitPandaParameterInstIr(inst: PandaParameterInstIr) { - pushParameter(result(inst), inst.index) - } - - override fun visitPandaLoadStaticInstIr(inst: PandaLoadStaticInstIr) { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - pushAssign(result(inst), PandaFieldRef(null, field)) - } - - override fun visitPandaLoadObjectInstIr(inst: PandaLoadObjectInstIr) { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - pushAssign(result(inst), PandaFieldRef(local(inst.inputs[0]), field)) - } - - override fun visitPandaStoreStaticInstIr(inst: PandaStoreStaticInstIr) { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - val fieldRef = PandaFieldRef(null, field) - val value = local(inst.inputs[1]) - pushAssign(fieldRef, value) - } - - override fun visitPandaStoreObjectInstIr(inst: PandaStoreObjectInstIr) { - val (instance, value) = inst.inputs.map { local(it) } - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - val fieldRef = PandaFieldRef(instance, field) - pushAssign(fieldRef, value) - } - - override fun visitPandaLoadArrayInstIr(inst: PandaLoadArrayInstIr) { - val (array, index) = inst.inputs.map { local(it) } - val arrayType = array.type - val type = if (arrayType is PandaArrayType) arrayType.elementType else project.objectClass.type - val arrayAccess = PandaArrayAccess(array, index, type) - pushAssign(result(inst), arrayAccess) - } - - override fun visitPandaStoreArrayInstIr(inst: PandaStoreArrayInstIr) { - val (array, index, value) = inst.inputs.map { local(it) } - val arrayType = array.type - val type = if (arrayType is PandaArrayType) arrayType.elementType else project.objectClass.type - val arrayAccess = PandaArrayAccess(array, index, type) - pushAssign(arrayAccess, value) - } - - override fun visitPandaCastInstIr(inst: PandaCastInstIr) { - val type = project.findType(inst.type) - val value = local(inst.inputs[0]) - val castExpr = PandaCastExpr(type, value) - pushAssign(result(inst), castExpr) - } - - override fun visitPandaIsInstanceInstIr(inst: PandaIsInstanceInstIr) { - val type = project.findType(inst.type) - val value = local(inst.inputs[0]) - val candidateType = project.findClassOrInterface(inst.candidateType).type - val isInstanceExpr = PandaIsInstanceExpr(type, value, candidateType) - pushAssign(result(inst), isInstanceExpr) - } - - override fun visitPandaCheckCastInstIr(inst: PandaCheckCastInstIr) { - val type = project.findClassOrInterface(inst.candidateType).type - val value = local(inst.inputs[0]) - val castExpr = PandaCastExpr(type, value) - pushAssign(result(inst), castExpr) - } - - override fun visitPandaBitcastInstIr(inst: PandaBitcastInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaIfImmInstIr(inst: PandaIfImmInstIr) { - val type = project.findType(inst.type) - val lhv = local(inst.inputs[0]) - val rhv = getConstant(inst.immediate, PandaPrimitives.find(inst.operandsType)) - val conditionExpr = getConditionType(inst.operator).invoke(type, lhv, rhv) - val (trueBranch, falseBranch) = blocks - .single { it.id == location.block } - .successors - .map { IrInstLocation(it, 0) } - pushIf(conditionExpr, trueBranch, falseBranch) - } - - override fun visitPandaCompareInstIr(inst: PandaCompareInstIr) { - val (lhv, rhv) = inst.inputs.map { local(it) } - val type = project.findType(inst.type) - val conditionExpr = getConditionType(inst.operator).invoke(type, lhv, rhv) - pushAssign(result(inst), conditionExpr) - } - - override fun visitPandaPhiInstIr(inst: PandaPhiInstIr) { - if (inst.users.isNotEmpty()) { - val inputs = inst.inputs.map { local(it) } - val blocks = inst.inputBlocks - pushPhi(result(inst), inputs, blocks) - } - } - - override fun visitPandaAddInstIr(inst: PandaAddInstIr) { - pushBinary(inst, ::PandaAddExpr) - } - - override fun visitPandaSubInstIr(inst: PandaSubInstIr) { - pushBinary(inst, ::PandaSubExpr) - } - - override fun visitPandaMulInstIr(inst: PandaMulInstIr) { - pushBinary(inst, ::PandaMulExpr) - } - - override fun visitPandaDivInstIr(inst: PandaDivInstIr) { - pushBinary(inst, ::PandaDivExpr) - } - - override fun visitPandaModInstIr(inst: PandaModInstIr) { - pushBinary(inst, ::PandaModExpr) - } - - override fun visitPandaAndInstIr(inst: PandaAndInstIr) { - pushBinary(inst, ::PandaAndExpr) - } - - override fun visitPandaOrInstIr(inst: PandaOrInstIr) { - pushBinary(inst, ::PandaOrExpr) - } - - override fun visitPandaXorInstIr(inst: PandaXorInstIr) { - pushBinary(inst, ::PandaXorExpr) - } - - override fun visitPandaShlInstIr(inst: PandaShlInstIr) { - pushBinary(inst, ::PandaShlExpr) - } - - override fun visitPandaShrInstIr(inst: PandaShrInstIr) { - pushBinary(inst, ::PandaShrExpr) - } - - override fun visitPandaAShlInstIr(inst: PandaAShlInstIr) { - pushBinary(inst, ::PandaAshlExpr) - } - - override fun visitPandaAShrInstIr(inst: PandaAShrInstIr) { - pushBinary(inst, ::PandaAshrExpr) - } - - override fun visitPandaCmpInstIr(inst: PandaCmpInstIr) { - pushBinary(inst, ::PandaCmpExpr) - } - - override fun visitPandaThrowInstIr(inst: PandaThrowInstIr) { - val error = local(inst.inputs[0]) - val catchers = inst.catchers - pushThrow(error, catchers) - } - - override fun visitPandaNegativeCheckInstIr(inst: PandaNegativeCheckInstIr) { - skip() - } - - override fun visitPandaSaveStateDeoptimizeInstIr(inst: PandaSaveStateDeoptimizeInstIr) { - skip() - } - - override fun visitPandaNegInstIr(inst: PandaNegInstIr) { - pushUnary(inst, ::PandaNegExpr) - } - - override fun visitPandaNotInstIr(inst: PandaNotInstIr) { - pushUnary(inst, ::PandaNotExpr) - } - - override fun visitPandaLenArrayInstIr(inst: PandaLenArrayInstIr) { - pushUnary(inst, ::PandaLenArrayExpr) - } - - override fun visitPandaBoundsCheckInstIr(inst: PandaBoundsCheckInstIr) { - skip() - } - - override fun visitPandaNullPtrInstIr(inst: PandaNullPtrInstIr) { - val nullPtr = PandaNull - pushAssign(result(inst), nullPtr) - } - - override fun visitPandaLoadUndefinedInstIr(inst: PandaLoadUndefinedInstIr) { - val undefined = PandaUndefined(project.findType("std.core.UndefinedType")) - pushAssign(result(inst), undefined) - } - - override fun visitPandaRefTypeCheckInstIr(inst: PandaRefTypeCheckInstIr) { - skip() - } - - override fun visitPandaTryInstIr(inst: PandaTryInstIr) { - skip() - } - - override fun visitPandaCatchPhiInstIr(inst: PandaCatchPhiInstIr) { - val inputs = inst.inputs.map { local(it) } - val throwers = inst.throwers - if (inst.inputs.isNotEmpty()) - pushCatchPhi(result(inst), inputs, throwers) - } - - override fun visitPandaIntrinsicInstIr(inst: PandaIntrinsicInstIr) { - val method = project.resolveIntrinsic(inst.intrinsicId) - val args = inst.inputs.dropLast(1).map { local(it) } - val callExpr = if (method != null) { - PandaStaticCallExpr(method, args) - } else { - PandaIntrinsicCallExpr(inst.intrinsicId, result(inst).type, args) - } - pushAssign(result(inst), callExpr) - } - - override fun visitPandaLoadFromConstantPoolInstIr(inst: PandaLoadFromConstantPoolInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaResolveStaticInstIr(inst: PandaResolveStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaResolveVirtualInstIr(inst: PandaResolveVirtualInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaCallDynamicInstIr(inst: PandaCallDynamicInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedVirtualInstIr(inst: PandaCallResolvedVirtualInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedStaticInstIr(inst: PandaCallResolvedStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaFillConstArrayInstIr(inst: PandaFillConstArrayInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaBuiltinInstIr(inst: PandaBuiltinInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldInstIr(inst: PandaLoadResolvedObjectFieldInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldStaticInstIr(inst: PandaLoadResolvedObjectFieldStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldInstIr(inst: PandaStoreResolvedObjectFieldInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldStaticInstIr(inst: PandaStoreResolvedObjectFieldStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjectDynamicInstIr(inst: PandaLoadObjectDynamicInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaStoreObjectDynamicInstIr(inst: PandaStoreObjectDynamicInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaFunctionImmediateInstIr(inst: PandaFunctionImmediateInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaHclassCheckInstIr(inst: PandaHclassCheckInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjFromConstInstIr(inst: PandaLoadObjFromConstInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadImmediateInstIr(inst: PandaLoadImmediateInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadRuntimeClassInstIr(inst: PandaLoadRuntimeClassInstIr) { - skip() - } - - override fun visitPandaLoadTypeInstIr(inst: PandaLoadTypeInstIr) { - val value = project.findType(inst.loadedType) - val type = project.typeClass.type - val typeConstant = PandaTypeConstant(value, type) - pushAssign(result(inst), typeConstant) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt deleted file mode 100644 index ecdcbe187..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaPrimitiveType -import org.jacodb.panda.staticvm.classpath.PandaType -import org.jacodb.panda.staticvm.ir.PandaAShlInstIr -import org.jacodb.panda.staticvm.ir.PandaAShrInstIr -import org.jacodb.panda.staticvm.ir.PandaAddInstIr -import org.jacodb.panda.staticvm.ir.PandaAndInstIr -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.ir.PandaBitcastInstIr -import org.jacodb.panda.staticvm.ir.PandaBoundsCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaBuiltinInstIr -import org.jacodb.panda.staticvm.ir.PandaCallDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCatchPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaCheckCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCmpInstIr -import org.jacodb.panda.staticvm.ir.PandaCompareInstIr -import org.jacodb.panda.staticvm.ir.PandaConstantInstIr -import org.jacodb.panda.staticvm.ir.PandaDivInstIr -import org.jacodb.panda.staticvm.ir.PandaFillConstArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaFunctionImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaHclassCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaIfImmInstIr -import org.jacodb.panda.staticvm.ir.PandaInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIrVisitor -import org.jacodb.panda.staticvm.ir.PandaIntrinsicInstIr -import org.jacodb.panda.staticvm.ir.PandaIsInstanceInstIr -import org.jacodb.panda.staticvm.ir.PandaLenArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadAndInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadFromConstantPoolInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjFromConstInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadRuntimeClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStringInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadTypeInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadUndefinedInstIr -import org.jacodb.panda.staticvm.ir.PandaModInstIr -import org.jacodb.panda.staticvm.ir.PandaMulInstIr -import org.jacodb.panda.staticvm.ir.PandaNegInstIr -import org.jacodb.panda.staticvm.ir.PandaNegativeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNewArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaNewObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaNotInstIr -import org.jacodb.panda.staticvm.ir.PandaNullCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNullPtrInstIr -import org.jacodb.panda.staticvm.ir.PandaOrInstIr -import org.jacodb.panda.staticvm.ir.PandaParameterInstIr -import org.jacodb.panda.staticvm.ir.PandaPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaRefTypeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnVoidInstIr -import org.jacodb.panda.staticvm.ir.PandaSafePointInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateDeoptimizeInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateInstIr -import org.jacodb.panda.staticvm.ir.PandaShlInstIr -import org.jacodb.panda.staticvm.ir.PandaShrInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaSubInstIr -import org.jacodb.panda.staticvm.ir.PandaThrowInstIr -import org.jacodb.panda.staticvm.ir.PandaTryInstIr -import org.jacodb.panda.staticvm.ir.PandaXorInstIr -import org.jacodb.panda.staticvm.ir.PandaZeroCheckInstIr - -sealed interface LocalVarNode { - val name: String -} - -open class LeafVarNode(override val name: String, val type: PandaType) : LocalVarNode - -class DependentVarNode(override val name: String, val bounds: List) : LocalVarNode - -class LoadArrayNode(override val name: String, val array: String) : LocalVarNode - -class ThisNode(name: String, type: PandaType) : LeafVarNode(name, type) - -class OutputVarBuilder( - private val method: PandaMethod, - private val block: PandaBasicBlockIr, - private val handledType: PandaType? = null, -) : PandaInstIrVisitor { - private val project = method.enclosingClass.project - - private fun default(inst: PandaInstIr): LeafVarNode { - val type = project.findType(inst.type) - return LeafVarNode(inst.id, type) - } - - // TODO: default(inst) - override fun visitPandaConstantInstIr(inst: PandaConstantInstIr): LocalVarNode { - val type = project.findType(inst.type) - return LeafVarNode(inst.id, type) - } - - override fun visitPandaSafePointInstIr(inst: PandaSafePointInstIr): LocalVarNode? = null - - override fun visitPandaSaveStateInstIr(inst: PandaSaveStateInstIr): LocalVarNode? = null - - override fun visitPandaNewObjectInstIr(inst: PandaNewObjectInstIr): LocalVarNode { - val classType = project.findClass(inst.objectClass).type - return LeafVarNode(inst.id, classType) - } - - override fun visitPandaNewArrayInstIr(inst: PandaNewArrayInstIr): LocalVarNode { - val arrayType = project.findType(inst.arrayType) - return LeafVarNode(inst.id, arrayType) - } - - override fun visitPandaCallStaticInstIr(inst: PandaCallStaticInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaCallLaunchStaticInstIr(inst: PandaCallLaunchStaticInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaNullCheckInstIr(inst: PandaNullCheckInstIr): LocalVarNode { - val bounds = inst.inputs.dropLast(1) - return DependentVarNode(inst.id, bounds) - } - - // TODO: default(inst) - override fun visitPandaZeroCheckInstIr(inst: PandaZeroCheckInstIr): LocalVarNode { - val type = project.findType(inst.type) - return LeafVarNode(inst.id, type) - } - - override fun visitPandaLoadStringInstIr(inst: PandaLoadStringInstIr): LocalVarNode { - val stringType = project.stringClass.type - return LeafVarNode(inst.id, stringType) - } - - override fun visitPandaLoadTypeInstIr(inst: PandaLoadTypeInstIr): LocalVarNode { - val typeType = project.typeClass.type - return LeafVarNode(inst.id, typeType) - } - - override fun visitPandaLoadRuntimeClassInstIr(inst: PandaLoadRuntimeClassInstIr): LocalVarNode? = null - - override fun visitPandaCallVirtualInstIr(inst: PandaCallVirtualInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaCallLaunchVirtualInstIr(inst: PandaCallLaunchVirtualInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaLoadAndInitClassInstIr(inst: PandaLoadAndInitClassInstIr): LocalVarNode? = null - - override fun visitPandaLoadClassInstIr(inst: PandaLoadClassInstIr): LocalVarNode? = null - - override fun visitPandaInitClassInstIr(inst: PandaInitClassInstIr): LocalVarNode? = null - - override fun visitPandaReturnVoidInstIr(inst: PandaReturnVoidInstIr): LocalVarNode? = null - - override fun visitPandaReturnInstIr(inst: PandaReturnInstIr): LocalVarNode? = null - - override fun visitPandaParameterInstIr(inst: PandaParameterInstIr): LocalVarNode = - if (inst.index == 0 && !method.flags.isStatic) { - ThisNode(inst.id, method.parameterTypes[inst.index]) - } else { - LeafVarNode(inst.id, method.parameterTypes[inst.index]) - } - - override fun visitPandaLoadStaticInstIr(inst: PandaLoadStaticInstIr): LocalVarNode { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - return LeafVarNode(inst.id, field.type) - } - - override fun visitPandaLoadObjectInstIr(inst: PandaLoadObjectInstIr): LocalVarNode { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - return LeafVarNode(inst.id, field.type) - } - - override fun visitPandaStoreStaticInstIr(inst: PandaStoreStaticInstIr): LocalVarNode? = null - - override fun visitPandaStoreObjectInstIr(inst: PandaStoreObjectInstIr): LocalVarNode? = null - - override fun visitPandaLoadArrayInstIr(inst: PandaLoadArrayInstIr): LocalVarNode { - val array = inst.inputs.first() - return LoadArrayNode(inst.id, array) - } - - override fun visitPandaStoreArrayInstIr(inst: PandaStoreArrayInstIr): LocalVarNode? = null - - override fun visitPandaCastInstIr(inst: PandaCastInstIr): LocalVarNode = default(inst) - - override fun visitPandaIsInstanceInstIr(inst: PandaIsInstanceInstIr): LocalVarNode = - LeafVarNode(inst.id, PandaPrimitiveType.BOOL) - - override fun visitPandaCheckCastInstIr(inst: PandaCheckCastInstIr): LocalVarNode { - val candidateType = project.findType(inst.candidateType) - return LeafVarNode(inst.id, candidateType) - } - - override fun visitPandaBitcastInstIr(inst: PandaBitcastInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaIfImmInstIr(inst: PandaIfImmInstIr): LocalVarNode? = null - - override fun visitPandaCompareInstIr(inst: PandaCompareInstIr): LocalVarNode = default(inst) - - override fun visitPandaPhiInstIr(inst: PandaPhiInstIr): LocalVarNode? = - DependentVarNode(inst.id, inst.inputs).takeIf { inst.users.isNotEmpty() } - - override fun visitPandaAddInstIr(inst: PandaAddInstIr): LocalVarNode = default(inst) - - override fun visitPandaSubInstIr(inst: PandaSubInstIr): LocalVarNode = default(inst) - - override fun visitPandaMulInstIr(inst: PandaMulInstIr): LocalVarNode = default(inst) - - override fun visitPandaDivInstIr(inst: PandaDivInstIr): LocalVarNode = default(inst) - - override fun visitPandaModInstIr(inst: PandaModInstIr): LocalVarNode = default(inst) - - override fun visitPandaAndInstIr(inst: PandaAndInstIr): LocalVarNode = default(inst) - - override fun visitPandaOrInstIr(inst: PandaOrInstIr): LocalVarNode = default(inst) - - override fun visitPandaXorInstIr(inst: PandaXorInstIr): LocalVarNode = default(inst) - - override fun visitPandaShlInstIr(inst: PandaShlInstIr): LocalVarNode = default(inst) - - override fun visitPandaShrInstIr(inst: PandaShrInstIr): LocalVarNode = default(inst) - - override fun visitPandaAShlInstIr(inst: PandaAShlInstIr): LocalVarNode = default(inst) - - override fun visitPandaAShrInstIr(inst: PandaAShrInstIr): LocalVarNode = default(inst) - - override fun visitPandaCmpInstIr(inst: PandaCmpInstIr): LocalVarNode = default(inst) - - override fun visitPandaThrowInstIr(inst: PandaThrowInstIr): LocalVarNode? = null - - override fun visitPandaNegativeCheckInstIr(inst: PandaNegativeCheckInstIr): LocalVarNode = default(inst) - - override fun visitPandaSaveStateDeoptimizeInstIr(inst: PandaSaveStateDeoptimizeInstIr): LocalVarNode? = null - - override fun visitPandaNegInstIr(inst: PandaNegInstIr): LocalVarNode = default(inst) - - override fun visitPandaNotInstIr(inst: PandaNotInstIr): LocalVarNode = default(inst) - - override fun visitPandaLenArrayInstIr(inst: PandaLenArrayInstIr): LocalVarNode = default(inst) - - override fun visitPandaBoundsCheckInstIr(inst: PandaBoundsCheckInstIr): LocalVarNode = default(inst) - - override fun visitPandaNullPtrInstIr(inst: PandaNullPtrInstIr): LocalVarNode { - val objectType = project.objectClass.type - return LeafVarNode(inst.id, objectType) - } - - override fun visitPandaLoadUndefinedInstIr(inst: PandaLoadUndefinedInstIr): LocalVarNode { - val undefinedType = project.undefinedClass.type - return LeafVarNode(inst.id, undefinedType) - } - - override fun visitPandaRefTypeCheckInstIr(inst: PandaRefTypeCheckInstIr): LocalVarNode { - val bounds = inst.inputs.take(1) - return DependentVarNode(inst.id, bounds) - } - - override fun visitPandaTryInstIr(inst: PandaTryInstIr): LocalVarNode? = null - - override fun visitPandaCatchPhiInstIr(inst: PandaCatchPhiInstIr): LocalVarNode? = - if (inst.inputs.isNotEmpty()) { - DependentVarNode(inst.id, inst.inputs).takeIf { inst.users.isNotEmpty() } - } else { - val throwableType = handledType ?: project.objectClass.type - LeafVarNode(inst.id, throwableType) - } - - override fun visitPandaIntrinsicInstIr(inst: PandaIntrinsicInstIr): LocalVarNode { - val type = project.resolveIntrinsic(inst.intrinsicId)?.returnType ?: project.objectClass.type - return LeafVarNode(inst.id, type) - } - - override fun visitPandaLoadFromConstantPoolInstIr(inst: PandaLoadFromConstantPoolInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaResolveStaticInstIr(inst: PandaResolveStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaResolveVirtualInstIr(inst: PandaResolveVirtualInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaCallDynamicInstIr(inst: PandaCallDynamicInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedVirtualInstIr(inst: PandaCallResolvedVirtualInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedStaticInstIr(inst: PandaCallResolvedStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaFillConstArrayInstIr(inst: PandaFillConstArrayInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaBuiltinInstIr(inst: PandaBuiltinInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldInstIr(inst: PandaLoadResolvedObjectFieldInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldStaticInstIr(inst: PandaLoadResolvedObjectFieldStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldInstIr(inst: PandaStoreResolvedObjectFieldInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldStaticInstIr(inst: PandaStoreResolvedObjectFieldStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjectDynamicInstIr(inst: PandaLoadObjectDynamicInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaStoreObjectDynamicInstIr(inst: PandaStoreObjectDynamicInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaFunctionImmediateInstIr(inst: PandaFunctionImmediateInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaHclassCheckInstIr(inst: PandaHclassCheckInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjFromConstInstIr(inst: PandaLoadObjFromConstInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadImmediateInstIr(inst: PandaLoadImmediateInstIr): LocalVarNode? { - TODO("Not yet implemented") - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt deleted file mode 100644 index 53af09867..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.cfg.CommonArgument -import org.jacodb.api.common.cfg.CommonArrayAccess -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonFieldRef -import org.jacodb.api.common.cfg.CommonInstanceCallExpr -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.panda.staticvm.classpath.PandaClassType -import org.jacodb.panda.staticvm.classpath.PandaField -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaPrimitiveType -import org.jacodb.panda.staticvm.classpath.PandaType - -sealed interface PandaExpr : CommonExpr { - val type: PandaType - - override val typeName: String - get() = type.typeName - - val operands: List -} - -sealed interface PandaValue : PandaExpr, CommonValue - -interface PandaSimpleValue : PandaValue { - override val operands: List - get() = emptyList() -} - -class PandaArgument( - val index: Int, - val name: String, - override val type: PandaType, -) : PandaSimpleValue, CommonArgument { - override fun toString(): String = "$name(${type.typeName})" -} - -sealed interface PandaLocalVar : PandaSimpleValue { - val name: String - override val type: PandaType -} - -class PandaLocalVarImpl( - override val name: String, - override val type: PandaType, -) : PandaLocalVar { - override fun toString(): String = name -} - -class PandaThis( - override val name: String, - override val type: PandaType, -) : PandaLocalVar, CommonThis { - override fun toString(): String = name -} - -class PandaFieldRef( - override val instance: PandaValue?, - val field: PandaField, -) : PandaValue, CommonFieldRef { - - override val type: PandaType - get() = this.field.type - - override val operands: List - get() = listOfNotNull(instance) - - override fun toString(): String = "${instance ?: field.enclosingClass.name}.${field.name}" -} - -class PandaArrayAccess( - override val array: PandaValue, - override val index: PandaValue, - override val type: PandaType, -) : PandaValue, CommonArrayAccess { - override val operands: List - get() = listOf(array, index) - - override fun toString(): String = "$array[$index]" -} - -sealed interface PandaConstant : PandaSimpleValue - -object PandaNull : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.NULL - - override fun toString(): String = "null" -} - -data class PandaUndefined(override val type: PandaType) : PandaConstant { - override fun toString(): String = "undefined" -} - -data class PandaBoolean( - val value: Boolean, -) : PandaConstant { - override val type: PandaPrimitiveType - get() = PandaPrimitiveType.BYTE - - override fun toString(): String = "$value" -} - -data class PandaByte( - val value: Byte, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.BYTE - - override fun toString(): String = "$value" -} - -data class PandaShort( - val value: Short, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.SHORT - - override fun toString(): String = "$value" -} - -data class PandaInt( - val value: Int, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.INT - - override fun toString(): String = "$value" -} - -data class PandaLong( - val value: Long, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.LONG - - override fun toString(): String = "$value" -} - -data class PandaUByte( - val value: UByte, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.UBYTE - - override fun toString(): String = "$value" -} - -data class PandaUShort( - val value: UShort, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.USHORT - - override fun toString(): String = "$value" -} - -data class PandaUInt( - val value: UInt, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.UINT - - override fun toString(): String = "$value" -} - -data class PandaULong( - val value: ULong, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.ULONG - - override fun toString(): String = "$value" -} - -data class PandaFloat( - val value: Float, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.FLOAT - - override fun toString(): String = "$value" -} - -data class PandaDouble( - val value: Double, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.DOUBLE - - override fun toString(): String = "$value" -} - -data class PandaString( - val value: String, - override val type: PandaClassType, // TODO: StringType (std.core.String) -) : PandaConstant { - override fun toString(): String = "\"$value\"" -} - -data class PandaTypeConstant( - val value: PandaType, - override val type: PandaType, // TODO: ClassType -) : PandaConstant { - override fun toString(): String = "${value}.class" -} - -data class PandaNewExpr( - override val type: PandaType, -) : PandaExpr { - override val operands: List - get() = emptyList() - - override fun toString(): String = "new ${type.typeName}" -} - -interface PandaUnaryExpr : PandaExpr { - val arg: PandaValue - - override val operands: List - get() = listOf(arg) -} - -data class PandaNegExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "-$arg" -} - -data class PandaNotExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "!$arg" -} - -data class PandaLenArrayExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "length($arg)" -} - -data class PandaCastExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "($type) $arg" -} - -data class PandaIsInstanceExpr( - override val type: PandaType, - override val arg: PandaValue, - val candidateType: PandaType, -) : PandaUnaryExpr { - override fun toString(): String = "$arg is $candidateType" -} - -sealed interface PandaBinaryExpr : PandaExpr { - val lhv: PandaValue - val rhv: PandaValue - - override val operands: List - get() = listOf(lhv, rhv) -} - -data class PandaAddExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv + $rhv" -} - -data class PandaSubExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv - $rhv" -} - -data class PandaMulExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv * $rhv" -} - -data class PandaDivExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv / $rhv" -} - -data class PandaModExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv % $rhv" -} - -data class PandaAndExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv & $rhv" -} - -data class PandaOrExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv | $rhv" -} - -data class PandaXorExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv ^ $rhv" -} - -data class PandaShlExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv << $rhv" -} - -data class PandaShrExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv >> $rhv" -} - -data class PandaAshlExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv a<< $rhv" -} - -data class PandaAshrExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv a>> $rhv" -} - -data class PandaCmpExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv cmp $rhv" -} - -interface PandaConditionExpr : PandaBinaryExpr - -data class PandaLeExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv <= $rhv" -} - -data class PandaLtExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv < $rhv" -} - -data class PandaGeExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv >= $rhv" -} - -data class PandaGtExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv > $rhv" -} - -data class PandaEqExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv == $rhv" -} - -data class PandaNeExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv != $rhv" -} - -sealed interface PandaCallExpr : PandaExpr, CommonCallExpr { - val method: PandaMethod - override val args: List - override val operands: List - get() = args -} - -data class PandaStaticCallExpr( - override val method: PandaMethod, - override val operands: List, -) : PandaCallExpr { - override val type: PandaType = method.returnType - - override val args: List - get() = operands - - override fun toString(): String = "${method.enclosingClass.name}::${method.name}(${operands.joinToString(", ")})" -} - -data class PandaIntrinsicCallExpr( - val intrinsic: String, - override val type: PandaType, - override val operands: List, -) : PandaExpr, CommonCallExpr { - override val args: List - get() = operands - - override fun toString(): String = "intrinsic<${intrinsic}>(${operands.joinToString(", ")})" -} - -data class PandaVirtualCallExpr( - override val method: PandaMethod, - override val instance: PandaValue, - override val operands: List, -) : PandaCallExpr, CommonInstanceCallExpr { - override val type: PandaType = method.returnType - - override val args: List - get() = operands - - override fun toString(): String = "${instance}.${method.name}(${operands.joinToString(", ")})" -} - -data class PandaPhiExpr( - override val type: PandaType, - val inputs: List, - val predecessors: List, -) : PandaExpr { - override val operands: List - get() = inputs - - override fun toString(): String = "Phi(${inputs.joinToString(", ")})" -} - -data class PandaNewArrayExpr( - override val type: PandaType, - val length: PandaValue, -) : PandaExpr { - override val operands: List - get() = listOf(length) - - override fun toString(): String = "new $type[$length]" -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt deleted file mode 100644 index 7e5476a74..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -fun PandaGraph.toDot(): String = buildString { - appendLine("digraph {") - appendLine(" rankdir=LR;") - appendLine(" compound=true;") - - instructions.forEachIndexed { index, inst -> - appendLine("\"inst_$index\" [shape=box, label=\"index=$index\\l${inst.toString().replace("\"", "\\\"")}\\l\"]") - } - - instructions.forEach { from -> - successors(from).forEach { to -> - appendLine("\"inst_${index(from)}\" -> \"inst_${index(to)}\"") - } - if (from is PandaTryPseudoInst) { - from.catchers.forEach { to -> - appendLine("\"inst_${index(from)}\" -> \"inst_${to.index}\" [label=\"catch\", style=\"dashed\"]") - } - } - } - - appendLine("}") -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt deleted file mode 100644 index 58542523e..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonGotoInst -import org.jacodb.api.common.cfg.CommonIfInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonInstLocation -import org.jacodb.api.common.cfg.CommonReturnInst -import org.jacodb.panda.staticvm.classpath.PandaMethod - -data class PandaInstLocation( - override val method: PandaMethod, - val index: Int, -) : CommonInstLocation { - // TODO: expand like JcInstLocation - - // override val lineNumber: Int - // get() = 0 // TODO("Not yet implemented") - - override fun toString(): String = "${method.name}:$index" -} - -data class PandaInstRef( - val index: Int, -) { - override fun toString(): String = index.toString() -} - -sealed interface PandaInst : CommonInst { - override val location: PandaInstLocation - - override val method: PandaMethod - get() = location.method - - // TODO: remove 'operands' - val operands: List -} - -class PandaDoNothingInst( - override val location: PandaInstLocation, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "NOP" -} - -class PandaParameterInst( - override val location: PandaInstLocation, - val lhv: PandaValue, - val index: Int, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "$lhv = arg$index" -} - -class PandaAssignInst( - override val location: PandaInstLocation, - override val lhv: PandaValue, - override val rhv: PandaExpr, -) : PandaInst, CommonAssignInst { - override val operands: List - get() = listOf(lhv, rhv) - - override fun toString(): String = "$lhv = $rhv" -} - -sealed interface PandaBranchingInst : PandaInst { - val successors: List -} - -class PandaIfInst( - override val location: PandaInstLocation, - val condition: PandaConditionExpr, - val trueBranch: PandaInstRef, - val falseBranch: PandaInstRef, -) : PandaBranchingInst, CommonIfInst { - override val operands: List - get() = listOf(condition) - - override val successors: List - get() = listOf(trueBranch, falseBranch) - - override fun toString(): String = "if ($condition) goto ${trueBranch.index} else goto ${falseBranch.index}" -} - -class PandaGotoInst( - override val location: PandaInstLocation, - val target: PandaInstRef, -) : PandaBranchingInst, CommonGotoInst { - override val operands: List - get() = emptyList() - - override val successors: List - get() = listOf(target) - - override fun toString(): String = "goto ${target.index}" -} - -sealed interface PandaTerminatingInst : PandaInst - -class PandaReturnInst( - override val location: PandaInstLocation, - override val returnValue: PandaValue?, -) : PandaTerminatingInst, CommonReturnInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = - if (returnValue != null) { - "return $returnValue" - } else { - "return" - } -} - -class PandaThrowInst( - override val location: PandaInstLocation, - val error: PandaValue, - val catchers: List, -) : PandaTerminatingInst { - override val operands: List - get() = listOf(error) - - override fun toString(): String = "throw $error" -} - -class PandaPhiInst( - override val location: PandaInstLocation, - val lhv: PandaValue, - val phiInputs: List, -) : PandaInst { - data class PhiInput(val value: PandaValue, val cfgBranch: PandaInstRef) - - val inputs: List - get() = phiInputs.map { it.value } - - override val operands: List - get() = inputs - - override fun toString() = "$lhv = Phi(${ - phiInputs.joinToString { "${it.value} <- ${it.cfgBranch}" } - })" -} - -class PandaCatchInst( - override val location: PandaInstLocation, - val throwable: PandaValue, - val throwers: List, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "catch($throwable: ${throwable.typeName})" -} - -class PandaTryPseudoInst( - override val location: PandaInstLocation, - val catchers: List, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "try" -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt deleted file mode 100644 index c67ea5061..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.cfg.InstList -import org.jacodb.api.common.cfg.MutableInstList - -class PandaInstList(override val instructions: List) : InstList { - override val size: Int - get() = instructions.size - override val indices: IntRange - get() = instructions.indices - override val lastIndex: Int - get() = instructions.lastIndex - - override fun get(index: Int): PandaInst = instructions[index] - - override fun getOrNull(index: Int): PandaInst? = instructions.getOrNull(index) - - override fun toMutableList(): MutableInstList = PandaMutableInstList(instructions.toMutableList()) - - override fun iterator(): Iterator = instructions.iterator() - - override fun toString(): String = instructions.joinToString(separator = "\n") { "${it.location.index}: $it" } -} - -data class PandaMutableInstList(override val instructions: MutableList) : MutableInstList { - override fun insertBefore(inst: PandaInst, vararg newInstructions: PandaInst) = - insertBefore(inst, newInstructions.toList()) - - override fun insertBefore(inst: PandaInst, newInstructions: Collection): Unit = - instructions.run { addAll(indexOf(inst), newInstructions) } - - override fun insertAfter(inst: PandaInst, vararg newInstructions: PandaInst) = - insertAfter(inst, newInstructions.toList()) - - override fun insertAfter(inst: PandaInst, newInstructions: Collection): Unit = - instructions.run { addAll(indexOf(inst) + 1, newInstructions) } - - override fun remove(inst: PandaInst): Boolean = instructions.remove(inst) - - override fun removeAll(inst: Collection): Boolean = instructions.removeAll(inst) - - override val size: Int - get() = instructions.size - override val indices: IntRange - get() = instructions.indices - override val lastIndex: Int - get() = instructions.lastIndex - - override fun get(index: Int): PandaInst = instructions[index] - - override fun getOrNull(index: Int): PandaInst? = instructions.getOrNull(index) - - override fun toMutableList(): MutableInstList = this - - override fun iterator(): Iterator = instructions.iterator() - -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt deleted file mode 100644 index 3c9a11eb4..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.classpath - -data class AccessFlags(val flags: Int) { - val isPublic: Boolean - get() = flags and 0x0001 > 0 - val isPrivate: Boolean - get() = flags and 0x0002 > 0 - val isProtected: Boolean - get() = flags and 0x0004 > 0 - val isPackagePrivate: Boolean - get() = false - val isStatic: Boolean - get() = flags and 0x0008 > 0 - val isFinal: Boolean - get() = flags and 0x0010 > 0 - val isInterface: Boolean - get() = flags and 0x0200 > 0 - val isAbstract: Boolean - get() = flags and 0x0400 > 0 - val isSynthetic: Boolean - get() = flags and 0x1000 > 0 -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt deleted file mode 100644 index 27cc5fa93..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.classpath - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.panda.staticvm.cfg.PandaGraph - -class PandaField( - val enclosingClass: PandaClassOrInterface, - val name: String, - val type: PandaType, - val flags: AccessFlags, -) { - val signature: String - get() = "${enclosingClass.name}.$name" -} - -class PandaMethod( - val signature: String, - override val name: String, - val enclosingClass: PandaClassOrInterface, - override val returnType: PandaType, - val parameterTypes: List, - val flags: AccessFlags, -) : CommonMethod { - - data class Parameter( - override val type: PandaType, - val index: Int, - // val method: PandaMethod, - ) : CommonMethodParameter { - val name: String? - get() = null - } - - override val parameters: List - get() = parameterTypes.mapIndexed { index, typeName -> - // Parameter(typeName, index, this) - Parameter(typeName, index) - } - - override fun flowGraph(): PandaGraph { - return enclosingClass.project.flowGraph(this) - } - - // TODO: equals - - override fun toString(): String { - return "${enclosingClass.name}::$name(${parameterTypes.joinToString { it.typeName }})" - } -} - -sealed interface PandaClassOrInterface { - val project: PandaProject - - val name: String - - val simpleName: String - get() = name.substringAfterLast('.') - - val directSuperClass: PandaClass? - val directSuperInterfaces: Set - - val declaredFields: HashMap - val declaredMethods: HashMap - - val flags: AccessFlags - - fun findFieldOrNull(name: String): PandaField? = - declaredFields[name] ?: directSuperClass?.findFieldOrNull(name) - - fun findMethodOrNull(name: String): PandaMethod? = - declaredMethods[name] ?: directSuperClass?.findMethodOrNull(name) - - fun findField(name: String) = requireNotNull(findFieldOrNull(name)) - fun findMethod(name: String) = requireNotNull(findMethodOrNull(name)) - - fun findMethodBySimpleNameOrNull(name: String): PandaMethod? = declaredMethods.values.find { it.name == name } - ?: directSuperClass?.findMethodBySimpleNameOrNull(name) - - fun findMethodBySimpleName(name: String) = requireNotNull(findMethodBySimpleNameOrNull(name)) - - val fields: List - get() = (directSuperClass?.fields ?: emptyList()) + declaredFields.values - - val methods: List - get() = (directSuperClass?.methods ?: emptyList()) + declaredMethods.values - - val type: PandaObjectType -} - -class PandaClass( - override val project: PandaProject, - override val name: String, - override val directSuperClass: PandaClass?, - override val directSuperInterfaces: Set, - override val flags: AccessFlags, - override val declaredFields: HashMap = hashMapOf(), - override val declaredMethods: HashMap = hashMapOf(), -) : PandaClassOrInterface { - override val type: PandaClassType - get() = PandaClassType(project, this) - - override fun toString(): String = name -} - -class PandaInterface( - override val project: PandaProject, - override val name: String, - override val directSuperInterfaces: Set, - override val flags: AccessFlags, - override val declaredFields: HashMap = hashMapOf(), - override val declaredMethods: HashMap = hashMapOf(), -) : PandaClassOrInterface { - override val directSuperClass: PandaClass? - get() = null - - override val type: PandaInterfaceType - get() = PandaInterfaceType(project, this) - - override fun toString(): String = name -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt deleted file mode 100644 index e0bcb4f54..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.classpath - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream - -object Intrinsics { - @Serializable - data class IntrinsicMethod( - val intrinsicId: String, - val className: String?, - val methodName: String?, - ) - - private val intrinsicsMapping: Map = run { - val resource = this::class.java.getResourceAsStream("/intrinsics.json") - ?: error("Intrinsics mapping not found") - - @OptIn(ExperimentalSerializationApi::class) - val intrinsics: List = Json.decodeFromStream(resource) - - intrinsics.associateBy { it.intrinsicId } - } - - fun resolve(id: String): Pair? = intrinsicsMapping[id]?.let { - if (it.className != null && it.methodName != null) { - Pair(it.className, it.methodName) - } else { - null - } - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt deleted file mode 100644 index 08b6c7e91..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.classpath - -enum class PandaPrimitiveType( - // override val project: PandaProject, - override val typeName: String, -) : PandaSingleType { - VOID("void"), - NULL("null"), - BOOL("u1"), - BYTE("i8"), - UBYTE("u8"), - SHORT("i16"), - USHORT("u16"), - INT("i32"), - UINT("u32"), - LONG("i64"), - ULONG("u64"), - FLOAT("f32"), - DOUBLE("f64"); - - override fun toString(): String = typeName - - override val nullable: Boolean? - get() = false -} - -object PandaPrimitives { - fun findPrimitiveOrNull(name: String): PandaPrimitiveType? = - enumValues().find { it.typeName == name } - - fun find(name: String) = requireNotNull(findPrimitiveOrNull(name)) { - "Not found primitive $name" - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt deleted file mode 100644 index c2d1e1893..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.classpath - -import org.jacodb.api.common.CommonProject -import org.jacodb.panda.staticvm.cfg.PandaGraph -import org.jacodb.panda.staticvm.ir.EtsStdlib -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.ir.PandaProgramIr - -class PandaProject : CommonProject { - - private val autoInitializedClasses = mutableListOf() - - private fun newBlankClass( - name: String, - parent: PandaClass?, - interfaces: Collection = emptySet(), - accessFlags: AccessFlags = AccessFlags(1), - ) = PandaClass( - project = this, - name = name, - directSuperClass = parent, - directSuperInterfaces = interfaces.toSet(), - flags = accessFlags, - ).also { autoInitializedClasses.add(it) } - - val objectClass = newBlankClass("std.core.Object", null) - val stringClass = newBlankClass("std.core.String", objectClass) - val undefinedClass = newBlankClass("std.core.Undefined", objectClass) - val typeClass = newBlankClass("std.core.Type", objectClass) - val voidClass = newBlankClass("std.core.Void", objectClass) - - private val classesIndex = hashMapOf>() - private val classesPool = hashSetOf() - - private val interfacesIndex = hashMapOf() - private val interfacesPool = hashSetOf() - - private val methodIndex = hashMapOf() - - init { - autoInitializedClasses.forEach { this.addClass(it) } - } - - private data class TreeEntry( - val depth: Int, - val parent: TreeEntry?, - val data: T, - ) - - fun addClass(node: PandaClass): Boolean { - if (classesIndex.containsKey(node.name)) - return false - - require(interfacesPool.containsAll(node.directSuperInterfaces)) - val parentNode = node.directSuperClass?.let { requireNotNull(classesIndex[it.name]) } - ?: classesIndex[objectClass.name] - - classesIndex[node.name] = TreeEntry(parentNode?.depth?.inc() ?: 0, parentNode, node) - classesPool.add(node) - return true - } - - fun addInterface(node: PandaInterface): Boolean { - require(interfacesPool.containsAll(node.directSuperInterfaces)) - interfacesPool.add(node) - return interfacesIndex.putIfAbsent(node.name, node) == null - } - - fun addField(field: PandaField): Boolean { - require(field.enclosingClass in classesPool) - return field.enclosingClass.declaredFields.putIfAbsent(field.name, field) == null - } - - fun addMethod(method: PandaMethod): Boolean { - require(method.enclosingClass in classesPool || method.enclosingClass in interfacesPool) - method.parameterTypes.forEach { - requireNotNull(findTypeOrNull(it.typeName)) { - "Not found type ${it.typeName}" - } - } - if (method.signature in methodIndex) return false - methodIndex[method.signature] = method - method.enclosingClass.declaredMethods[method.signature] = method - return true - } - - fun addFlowGraph(method: PandaMethod, basicBlocksInfo: List): Boolean { - require(method.enclosingClass in classesPool || method.enclosingClass in interfacesPool) - // TODO: use lazy putIfAbsent - return flowGraphs.putIfAbsent(method, PandaGraph.of(method, basicBlocksInfo)) == null - } - - fun findClassOrNull(name: String): PandaClass? = classesIndex[name]?.data - fun findInterfaceOrNull(name: String): PandaInterface? = interfacesIndex[name] - fun findClassOrInterfaceOrNull(name: String): PandaClassOrInterface? = - classesIndex[name]?.data ?: interfacesIndex[name] - - fun findMethod(name: String): PandaMethod = requireNotNull(methodIndex[name]) { - "Not found method $name" - } - - companion object { - fun fromProgramIr(program: PandaProgramIr, withStdLib: Boolean = false): PandaProject { - val project = PandaProject() - if (withStdLib) { - project.addProgramIr(EtsStdlib.program) - } - project.addProgramIr(program) - return project - } - } - - fun addProgramIr(program: PandaProgramIr) { - program.addInterfacesHierarchyToPandaClasspath(this) - program.addClassesHierarchyToPandaClasspath(this) - program.addFieldsToPandaClasspath(this) - program.addMethodsToPandaClasspath(this) - program.addFlowGraphsToPandaClasspath(this) - } - - fun findTypeOrNull(name: String): PandaType? = - if (name.endsWith("[]")) { - findTypeOrNull(name.removeSuffix("[]"))?.array - } else { - PandaPrimitives.findPrimitiveOrNull(name) ?: findClassOrInterfaceOrNull(name)?.type - } - - fun findType(name: String) = requireNotNull(findTypeOrNull(name)) { - "Not found type $name" - } - - fun findClass(name: String) = requireNotNull(findClassOrNull(name)) { - "Not found class $name" - } - - fun findClassOrInterface(name: String) = requireNotNull(findClassOrInterfaceOrNull(name)) { - "Not found class or interface $name" - } - - fun getElementType(name: String): PandaType = - if (name.endsWith("[]")) { - findType(name.removeSuffix("[]")) - } else { - throw IllegalArgumentException("Expected array type") - } - - private val flowGraphs: MutableMap = hashMapOf() - - val classes: List - get() = classesIndex.values.map { it.data } - - val methods: List - get() = methodIndex.values.toList() - - // TODO: why PUT empty graph? why not just use 'flowGraphs[method] ?: PandaGraph.empty()' - fun flowGraph(method: PandaMethod): PandaGraph = flowGraphs.getOrPut(method) { PandaGraph.empty() } - - private fun ancestors(node: TreeEntry): List = - (node.parent?.let { ancestors(it) } ?: emptyList()).plus(node.data.type) - - fun commonClassType(types: Collection): PandaClassType? { - if (types.isEmpty()) return objectClass.type - val nodes = types.map { - requireNotNull(classesIndex[it.typeName]) { - "Not found class ${it.typeName}" - } - } - val paths = nodes.map { ancestors(it) } - return paths.reduce { p1, p2 -> - p1.zip(p2) { t1, t2 -> t1.takeIf { t1 == t2 } }.filterNotNull() - }.lastOrNull() - } - - fun commonType(types: Collection): PandaType? { - if (types.any { it is PandaArrayType }) { - return types.takeIf { it.all { it is PandaArrayType } } - ?.filterIsInstance() - ?.map { it.elementType } - ?.let(this::commonType) - ?.array - ?: objectClass.type - } - if (types.any { it is PandaPrimitiveType }) { - return types.takeIf { it.all { it is PandaPrimitiveType } } - ?.filterIsInstance() - ?.max() - } - return commonClassType(types.filterIsInstance()) - } - - fun resolveIntrinsic(id: String) = Intrinsics.resolve(id)?.let { (className, methodName) -> - findClassOrInterface(className).findMethodBySimpleName(methodName) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt deleted file mode 100644 index aff82a755..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.classpath - -import org.jacodb.api.common.CommonType -import org.jacodb.api.common.CommonTypeName - -sealed interface PandaType : CommonType, CommonTypeName { - val array: PandaArrayType -} - -data class PandaArrayType( - val dimensions: Int, - private val wrappedType: PandaSingleType, -) : PandaType { - init { - require(dimensions > 0) { "Cannot create array with $dimensions dimensions" } - } - - override val typeName: String - get() = wrappedType.typeName + "[]".repeat(dimensions) - - override val nullable: Boolean - get() = true - - val elementType: PandaType - get() = if (dimensions == 1) { - wrappedType - } else { - PandaArrayType(dimensions - 1, wrappedType) - } - - override val array: PandaArrayType - get() = PandaArrayType(dimensions + 1, wrappedType) - - override fun toString(): String = "$elementType[]" -} - -/** any kind of non-array type */ -sealed interface PandaSingleType : PandaType { - override val array: PandaArrayType - get() = PandaArrayType(1, this) -} - -sealed interface PandaObjectType : PandaSingleType { - val project: PandaProject - - val pandaClassOrInterface: PandaClassOrInterface - - override val typeName: String - get() = pandaClassOrInterface.name - - override val nullable: Boolean - get() = true -} - -data class PandaClassType( - override val project: PandaProject, - override val pandaClassOrInterface: PandaClass, -) : PandaObjectType { - override fun toString(): String = pandaClassOrInterface.name -} - -data class PandaInterfaceType( - override val project: PandaProject, - override val pandaClassOrInterface: PandaInterface, -) : PandaObjectType { - override fun toString(): String = pandaClassOrInterface.name -} - -data class PandaUnionType( - val types: Set, -) : PandaSingleType { - init { - require(types.isNotEmpty()) { "Cannot create empty union type" } - } - - override val typeName: String - get() = types.joinToString(" | ") { it.typeName } - - override val nullable: Boolean - get() = TODO() - - val methods: List - get() = types.flatMap { if (it is PandaObjectType) it.pandaClassOrInterface.methods else emptyList() } - - override fun toString(): String = typeName -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt deleted file mode 100644 index 5a845dd07..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ets - -data class Parameter( - val td: TypeDesc, - val name: String, - val attributes: Attributes, -) { - val type: Type - get() = Type.resolve(td)!! - - fun isRest(): Boolean = attributes.isRest() - fun isOptional(): Boolean = attributes.isOptional() - - override fun toString(): String = "$name: $type" -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt deleted file mode 100644 index 52ec0ab87..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ets - -/** - * Type descriptor. - * - * ``` - * TypeDescriptor -> PrimitiveType | ArrayType | RefType - * PrimitiveType -> 'Z' | 'B' | 'H' | 'S' | 'C' | 'I' | 'U' | 'J' | 'Q' | 'F' | 'D' | 'A' - * ArrayType -> '[' TypeDescriptor - * RefType -> 'L' ClassName ';' - * ``` - * - * `PrimitiveType` is a one letter encoding for primitive type - * - * | Type | Encoding | - * | ---- | :--: | - * | `u1` | `Z` | - * | `i8` | `B` | - * | `u8` | `H` | - * | `i16` | `S` | - * | `u16` | `C` | - * | `i32` | `I` | - * | `u32` | `U` | - * | `f32` | `F` | - * | `f64` | `D` | - * | `i64` | `J` | - * | `u64` | `Q` | - * | `any` | `A` | - * - * `ClassName` is a qualified name of a class with `.` replaced with `/`. - */ -data class TypeDesc(val typeDesc: String) { - override fun toString(): String = typeDesc - - fun getKind(): TypeKind { - return if (this == NULL) { - TypeKind.NULL - } else if (typeDesc[0] == 'M') { - TypeKind.METHOD - } else if (typeDesc[0] == 'V') { - TypeKind.VOID - } else if (typeDesc[0] == '[') { - TypeKind.ARRAY - } else if (typeDesc[0] == 'L') { - check(typeDesc.last() == ';') - val className = typeDesc.substring(1, typeDesc.length - 1) - when (className) { - "std/core/Boolean" -> { - TypeKind.BOOLEAN - } - - "std/core/Byte" -> { - TypeKind.BYTE - } - - "std/core/Char" -> { - TypeKind.CHAR - } - - "std/core/Short" -> { - TypeKind.SHORT - } - - "std/core/Int" -> { - TypeKind.INT - } - - "std/core/Long" -> { - TypeKind.LONG - } - - "std/core/Float" -> { - TypeKind.FLOAT - } - - "std/core/Double" -> { - TypeKind.DOUBLE - } - - "std/core/__internal_undefined" -> { - TypeKind.UNDEFINED - } - - else -> { - TypeKind.CLASS - } - } - } else when (this) { - ValueTypeDesc.BOOLEAN -> TypeKind.BOOLEAN - ValueTypeDesc.BYTE -> TypeKind.BYTE - ValueTypeDesc.SHORT -> TypeKind.SHORT - ValueTypeDesc.CHAR -> TypeKind.CHAR - ValueTypeDesc.INT -> TypeKind.INT - ValueTypeDesc.LONG -> TypeKind.LONG - ValueTypeDesc.FLOAT -> TypeKind.FLOAT - ValueTypeDesc.DOUBLE -> TypeKind.DOUBLE - else -> TypeKind.NONE - } - } - - fun isValueType(): Boolean { - TODO() - } - - fun getArrayElementType(): TypeDesc { - TODO() - } - - companion object { - val U1: TypeDesc = TypeDesc("Z") - val I8: TypeDesc = TypeDesc("B") - val U8: TypeDesc = TypeDesc("H") - val I16: TypeDesc = TypeDesc("S") - val U16: TypeDesc = TypeDesc("C") - val I32: TypeDesc = TypeDesc("I") - val U32: TypeDesc = TypeDesc("U") - val F32: TypeDesc = TypeDesc("F") - val F64: TypeDesc = TypeDesc("D") - val I64: TypeDesc = TypeDesc("J") - val U64: TypeDesc = TypeDesc("Q") - val ANY: TypeDesc = TypeDesc("A") - val NULL: TypeDesc = TypeDesc("Null") - fun array(elemType: TypeDesc): TypeDesc = TypeDesc("[$elemType") - fun ref(className: String): TypeDesc = TypeDesc("L${className.replace('.', '/')};") - } -} - -/** - * Type kind. - */ -enum class TypeKind(val value: Byte) { - NONE(0x0), - VOID(0x1), - - CHAR(0x2), - BOOLEAN(0x3), - BYTE(0x4), - SHORT(0x5), - INT(0x6), - LONG(0x7), - FLOAT(0x8), - DOUBLE(0x9), - - CLASS(0xA), - STRING(0xB), - INTERFACE(0xC), - ARRAY(0xD), - TUPLE(0xE), - LAMBDA(0xF), - METHOD(0x10), - - UNION(0x11), - UNDEFINED(0x12), - NULL(0x13), - - ENUM(0x14), -} - -/** - * Value type descriptor. - */ -object ValueTypeDesc { - val BOOLEAN: TypeDesc = TypeDesc.U1 - val BYTE: TypeDesc = TypeDesc.I8 - val SHORT: TypeDesc = TypeDesc.I16 - val CHAR: TypeDesc = TypeDesc.U16 - val INT: TypeDesc = TypeDesc.I32 - val LONG: TypeDesc = TypeDesc.I64 - val FLOAT: TypeDesc = TypeDesc.F32 - val DOUBLE: TypeDesc = TypeDesc.F64 -} - -val OBJECT_TYPE_DESC = TypeDesc.ref("std.core.Object") - -val ObjectType = ClassType(OBJECT_TYPE_DESC, Attributes(0)) - -/** - * Attribute flags. - */ -data class Attributes(val value: Int) { - - fun isStatic(): Boolean = (value and STATIC) != 0 - fun isInherited(): Boolean = (value and INHERITED) != 0 - fun isReadOnly(): Boolean = (value and READONLY) != 0 - fun isFinal(): Boolean = (value and FINAL) != 0 - fun isAbstract(): Boolean = (value and ABSTRACT) != 0 - fun isConstructor(): Boolean = (value and CONSTRUCTOR) != 0 - fun isRest(): Boolean = (value and REST) != 0 - fun isOptional(): Boolean = (value and OPTIONAL) != 0 - fun isThrowing(): Boolean = (value and THROWING) != 0 - fun isNative(): Boolean = (value and NATIVE) != 0 - fun isAsync(): Boolean = (value and ASYNC) != 0 - fun isNeverResult(): Boolean = (value and NEVERRESULT) != 0 - fun isGetter(): Boolean = (value and GETTER) != 0 - fun isSetter(): Boolean = (value and SETTER) != 0 - - companion object { - const val STATIC: Int = 1 shl 0 - const val INHERITED: Int = 1 shl 1 - const val READONLY: Int = 1 shl 2 - const val FINAL: Int = 1 shl 3 - const val ABSTRACT: Int = 1 shl 4 - const val CONSTRUCTOR: Int = 1 shl 5 - const val REST: Int = 1 shl 6 - const val OPTIONAL: Int = 1 shl 7 - const val THROWING: Int = 1 shl 8 - const val NATIVE: Int = 1 shl 9 - const val ASYNC: Int = 1 shl 10 - const val NEVERRESULT: Int = 1 shl 11 - const val GETTER: Int = 1 shl 12 - const val SETTER: Int = 1 shl 13 - } -} - -/** - * Access modifier. - */ -enum class AccessModifier(val value: Byte) { - PUBLIC(0), - PRIVATE(1), - PROTECTED(2), -} - -abstract class Type { - abstract val td: TypeDesc - - abstract fun isPrimitive(): Boolean - abstract fun isReference(): Boolean - abstract fun hasName(): Boolean - abstract fun getName(): String - abstract fun getLiteral(): String - - /** - * Checks if this type is a subtype of another type. - * - * `T.subTypeOf(U)` means `T extends U` - */ - open fun subTypeOf(other: Type): Boolean { - if (this == other) return true - if (other == ObjectType) { - val isNullish = this is UndefinedType || this is NullType - return this.isReference() && !isNullish - } - return false - } - - /** - * Checks if this type is assignable from another type. - * - * `T.assignableFrom(U)` means `T <- U` - */ - open fun assignableFrom(other: Type): Boolean { - if (other.subTypeOf(this)) return true - if (this.isNumericType() && other.isNumericType()) return true - return false - } - - private fun isNumericType(): Boolean = - this is ByteType - || this is ShortType - || this is IntType - || this is LongType - || this is FloatType - || this is DoubleType - - override fun toString(): String = if (hasName()) getName() else getLiteral() - - companion object { - fun resolve(td: TypeDesc): Type? { - return when (td.getKind()) { - TypeKind.NONE -> null - TypeKind.VOID -> VoidType.REF - TypeKind.CHAR -> TODO() - TypeKind.BOOLEAN -> TODO() - TypeKind.BYTE -> TODO() - TypeKind.SHORT -> TODO() - TypeKind.INT -> TODO() - TypeKind.LONG -> TODO() - TypeKind.FLOAT -> TODO() - TypeKind.DOUBLE -> TODO() - TypeKind.CLASS -> TODO() - TypeKind.STRING -> TODO() - TypeKind.INTERFACE -> TODO() - TypeKind.ARRAY -> TODO() - TypeKind.TUPLE -> TODO() - TypeKind.LAMBDA -> TODO() - TypeKind.METHOD -> TODO() - TypeKind.UNION -> TODO() - TypeKind.UNDEFINED -> TODO() - TypeKind.NULL -> TODO() - TypeKind.ENUM -> TODO() - // else -> null - } - } - } -} - -class NullType private constructor( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = "null" - override fun getLiteral(): String = "null" - - override fun equals(other: Any?): Boolean { - return other is NullType - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val REF: NullType = NullType(TypeDesc.NULL) - } -} - -class UndefinedType private constructor( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = "undefined" - override fun getLiteral(): String = "undefined" - - override fun equals(other: Any?): Boolean { - return other is UndefinedType - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val REF: UndefinedType = UndefinedType(TypeDesc("undefined")) - } -} - -class VoidType private constructor( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = "void" - override fun getLiteral(): String = "void" - - override fun equals(other: Any?): Boolean { - return other is VoidType - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val REF: VoidType = VoidType(TypeDesc("void")) - } -} - -class CharType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "char" else "Char" - - override fun equals(other: Any?): Boolean { - return other is CharType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: CharType = CharType(ValueTypeDesc.CHAR, true) - val REF: CharType = CharType(TypeDesc.ref("std.core.Char"), false) - } -} - -class BooleanType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "boolean" else "Boolean" - - override fun equals(other: Any?): Boolean { - return other is BooleanType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: BooleanType = BooleanType(ValueTypeDesc.BOOLEAN, true) - val REF: BooleanType = BooleanType(TypeDesc.ref("std.core.Boolean"), false) - } -} - -class ByteType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "byte" else "Byte" - - override fun equals(other: Any?): Boolean { - return other is ByteType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: ByteType = ByteType(ValueTypeDesc.BYTE, true) - val REF: ByteType = ByteType(TypeDesc.ref("std.core.Byte"), false) - } -} - -class ShortType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "short" else "Short" - - override fun equals(other: Any?): Boolean { - return other is ShortType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: ShortType = ShortType(ValueTypeDesc.SHORT, true) - val REF: ShortType = ShortType(TypeDesc.ref("std.core.Short"), false) - } -} - -class IntType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "int" else "Int" - - companion object { - val VAL: IntType = IntType(ValueTypeDesc.INT, true) - val REF: IntType = IntType(TypeDesc.ref("std.core.Int"), false) - } -} - -class LongType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "long" else "Long" - - override fun equals(other: Any?): Boolean { - return other is LongType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: LongType = LongType(ValueTypeDesc.LONG, true) - val REF: LongType = LongType(TypeDesc.ref("std.core.Long"), false) - } -} - -class FloatType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "float" else "Float" - - override fun equals(other: Any?): Boolean { - return other is FloatType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: FloatType = FloatType(ValueTypeDesc.FLOAT, true) - val REF: FloatType = FloatType(TypeDesc.ref("std.core.Float"), false) - } -} - -class DoubleType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "double" else "Double" - - override fun equals(other: Any?): Boolean { - return other is DoubleType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: DoubleType = DoubleType(ValueTypeDesc.DOUBLE, true) - val REF: DoubleType = DoubleType(TypeDesc.ref("std.core.Double"), false) - } -} - -class ClassType( - override val td: TypeDesc, - val attrs: Attributes, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = td.toString() - override fun getLiteral(): String = "class {...}" // TODO - - fun getBaseType(): ClassType { - TODO() - } - - fun isFinal(): Boolean = attrs.isFinal() - - override fun subTypeOf(other: Type): Boolean { - if (super.subTypeOf(other)) return true - if (other is ClassType) { - var bt = this - while (bt != bt.getBaseType()) { - if (bt == other) return true - bt = bt.getBaseType() - } - return false - } - // if (other is InterfaceType) { - // TODO() - // } - return false - } - - override fun equals(other: Any?): Boolean { - return other is ClassType && other.td == this.td - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -// TODO: InterfaceType - -class ArrayType( - override val td: TypeDesc, - val elemTD: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - override fun getLiteral(): String = "${getElementType()}[]" - - fun getElementType(): Type { - // TODO: return Type.resolve(elemTD)!! - TODO() - } - - override fun assignableFrom(other: Type): Boolean { - if (super.assignableFrom(other)) return true - if (other is ArrayType) { - return this.getElementType().subTypeOf(other.getElementType()) - } - return false - } - - override fun equals(other: Any?): Boolean { - if (other is ArrayType) { - return this.getElementType() == other.getElementType() - } - return false - } - - override fun hashCode(): Int { - return elemTD.hashCode() - } - - companion object { - private fun arrayWithElements(elemTD: TypeDesc): ArrayType = ArrayType(TypeDesc.array(elemTD), elemTD) - - val BOOLEAN_VAL: ArrayType = arrayWithElements(ValueTypeDesc.BOOLEAN) - val BOOLEAN_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Boolean")) - val CHAR_VAL: ArrayType = arrayWithElements(ValueTypeDesc.CHAR) - val CHAR_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Char")) - val BYTE_VAL: ArrayType = arrayWithElements(ValueTypeDesc.BYTE) - val BYTE_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Byte")) - val SHORT_VAL: ArrayType = arrayWithElements(ValueTypeDesc.SHORT) - val SHORT_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Short")) - val INT_VAL: ArrayType = arrayWithElements(ValueTypeDesc.INT) - val INT_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Int")) - val LONG_VAL: ArrayType = arrayWithElements(ValueTypeDesc.LONG) - val LONG_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Long")) - val FLOAT_VAL: ArrayType = arrayWithElements(ValueTypeDesc.FLOAT) - val FLOAT_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Float")) - val DOUBLE_VAL: ArrayType = arrayWithElements(ValueTypeDesc.DOUBLE) - val DOUBLE_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Double")) - - internal fun getInstance(td: TypeDesc, elemTD: TypeDesc): ArrayType { - return when (elemTD.getKind()) { - TypeKind.BOOLEAN -> if (elemTD.isValueType()) BOOLEAN_VAL else BOOLEAN_REF - TypeKind.CHAR -> if (elemTD.isValueType()) CHAR_VAL else CHAR_REF - TypeKind.BYTE -> if (elemTD.isValueType()) BYTE_VAL else BYTE_REF - TypeKind.SHORT -> if (elemTD.isValueType()) SHORT_VAL else SHORT_REF - TypeKind.INT -> if (elemTD.isValueType()) INT_VAL else INT_REF - TypeKind.LONG -> if (elemTD.isValueType()) LONG_VAL else LONG_REF - TypeKind.FLOAT -> if (elemTD.isValueType()) FLOAT_VAL else FLOAT_REF - TypeKind.DOUBLE -> if (elemTD.isValueType()) DOUBLE_VAL else DOUBLE_REF - TypeKind.CLASS -> ArrayType(td, elemTD) - TypeKind.INTERFACE -> ArrayType(td, elemTD) - TypeKind.STRING -> ArrayType(td, elemTD) - TypeKind.ARRAY -> ArrayType(td, elemTD) - TypeKind.TUPLE -> ArrayType(td, elemTD) - TypeKind.LAMBDA -> ArrayType(td, elemTD) - TypeKind.METHOD -> ArrayType(td, elemTD) - TypeKind.UNION -> ArrayType(td, elemTD) - else -> error("Cannot create ArrayType with element type $elemTD") - } - } - - internal fun getInstance(td: TypeDesc): ArrayType { - return getInstance(td, td.getArrayElementType()) - } - } -} - -// TODO: TupleType - -abstract class FunctionType( - override val td: TypeDesc, - val attrs: Attributes, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - - fun getResultType(): Type { - // TODO: return Type.resolve(td.getResultType()) - TODO() - } - - fun isThrowing(): Boolean = attrs.isThrowing() - fun isNative(): Boolean = attrs.isNative() - fun isAsync(): Boolean = attrs.isAsync() - fun isNeverResult(): Boolean = attrs.isNeverResult() - - override fun equals(other: Any?): Boolean { - return other is FunctionType && other.td == this.td - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -class LambdaType( - td: TypeDesc, - attrs: Attributes, -) : FunctionType(td, attrs) { - - override fun getLiteral(): String = buildString { - append("(") - append("...TODO...") - // TODO: - // val paramsNum = getParametersNum() - // for (i in 0 until paramsNum) { - // if (i > 0) { - // append(", ") - // } - // append(getParameter(i)) - // } - append("): ") - append(getResultType()) - } - - fun getReceiverType(): Type { - // TODO: return Type.resolve(td.getReceiverType()) - TODO() - } - - fun getParametersNum(): Int { - TODO() - } - - fun getParameter(index: Int): Parameter { - TODO() - } - - override fun assignableFrom(other: Type): Boolean { - if (super.assignableFrom(other)) return true - if (other !is LambdaType) return false - - if (this.getParametersNum() != other.getParametersNum()) return false - - // Parameter types are using contravariance - for (i in 0 until this.getParametersNum()) { - // if (this.getParameter(i) != other.getParameter(i)) return false - val lt = this.getParameter(i).type - val rt = other.getParameter(i).type - if (!lt.subTypeOf(rt)) return false - } - - // Return types are using covariance - return other.getResultType().subTypeOf(this.getResultType()) - } -} - -class MethodType( - td: TypeDesc, - attrs: Attributes, -) : FunctionType(td, attrs) { - - override fun getLiteral(): String = buildString { - append("(") - append("...TODO...") - append("): ") - append(getResultType()) - } - - fun getReceiverType(): Type { - // TODO: return Type.resolve(td.getReceiverType()) - TODO() - } - - override fun assignableFrom(other: Type): Boolean { - return false - } -} - -class StringType( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - override fun getLiteral(): String = "string" // TODO - - override fun equals(other: Any?): Boolean { - return other is StringType - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -class EnumType( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = false - override fun hasName(): Boolean = true - override fun getName(): String = td.toString() - override fun getLiteral(): String = "enum {...}" // TODO - - override fun assignableFrom(other: Type): Boolean { - if (super.assignableFrom(other)) return true - if (other is EnumType) { - return this.getName() == other.getName() - } - return false - } - - override fun equals(other: Any?): Boolean { - // TODO - return false - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -class UnionType( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - override fun getLiteral(): String = "(... | ...)" // TODO - - override fun equals(other: Any?): Boolean { - // TODO - return false - } - - override fun hashCode(): Int { - return td.hashCode() - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt deleted file mode 100644 index 5aab28aff..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ir - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.decodeFromStream - -@OptIn(ExperimentalSerializationApi::class) -object EtsStdlib { - val program: PandaProgramIr - - init { - val stream = this::class.java.getResourceAsStream("/stdlib.ir") - ?: error("Not found stdlib, run arkcompiler fork: \"es2panda --dump-ir --gen-stdlib > stdlib.ir\"") - program = PandaProgramIr.json.decodeFromStream(stream) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt deleted file mode 100644 index 0aa45b0eb..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt +++ /dev/null @@ -1,1269 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ir - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -sealed interface PandaInstIr { - val id: String - val inputs: List - val users: List - val opcode: String - val type: String - val catchers: List - val visit: String - - fun accept(visitor: PandaInstIrVisitor): T -} - -@Serializable -sealed interface PandaComparisonInstIr : PandaInstIr { - val operator: String - val operandsType: String -} - -@Serializable -sealed interface PandaWithPropertyInstIr : PandaInstIr { - val enclosingClass: String - val field: String -} - -@Serializable -sealed interface PandaTerminatingInstIr : PandaInstIr - -@Serializable -@SerialName("Constant") -data class PandaConstantInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val value: ULong, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaConstantInstIr(this) -} - -@Serializable -@SerialName("SafePoint") -data class PandaSafePointInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSafePointInstIr(this) -} - -@Serializable -@SerialName("SaveState") -data class PandaSaveStateInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSaveStateInstIr(this) -} - -@Serializable -@SerialName("NewObject") -data class PandaNewObjectInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val objectClass: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNewObjectInstIr(this) -} - -@Serializable -@SerialName("NewArray") -data class PandaNewArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val arrayType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNewArrayInstIr(this) -} - -@Serializable -@SerialName("CallStatic") -data class PandaCallStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallStaticInstIr(this) -} - -@Serializable -@SerialName("NullCheck") -data class PandaNullCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNullCheckInstIr(this) -} - -@Serializable -@SerialName("ZeroCheck") -data class PandaZeroCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaZeroCheckInstIr(this) -} - -@Serializable -@SerialName("LoadString") -data class PandaLoadStringInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val string: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadStringInstIr(this) -} - -@Serializable -@SerialName("LoadType") -data class PandaLoadTypeInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val loadedType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadTypeInstIr(this) -} - -@Serializable -@SerialName("LoadRuntimeClass") -data class PandaLoadRuntimeClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val loadedClass: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadRuntimeClassInstIr(this) -} - -@Serializable -@SerialName("CallVirtual") -data class PandaCallVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallVirtualInstIr(this) -} - -@Serializable -@SerialName("CallLaunchVirtual") -data class PandaCallLaunchVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallLaunchVirtualInstIr(this) -} - -@Serializable -@SerialName("CallLaunchStatic") -data class PandaCallLaunchStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallLaunchStaticInstIr(this) -} - -@Serializable -@SerialName("LoadAndInitClass") -data class PandaLoadAndInitClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val loadedClass: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadAndInitClassInstIr(this) -} - -@Serializable -@SerialName("LoadClass") -data class PandaLoadClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadClassInstIr(this) -} - -@Serializable -@SerialName("InitClass") -data class PandaInitClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaInitClassInstIr(this) -} - -@Serializable -@SerialName("ReturnVoid") -data class PandaReturnVoidInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaTerminatingInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaReturnVoidInstIr(this) -} - -@Serializable -@SerialName("Return") -data class PandaReturnInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaTerminatingInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaReturnInstIr(this) -} - -@Serializable -@SerialName("Parameter") -data class PandaParameterInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val index: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaParameterInstIr(this) -} - -@Serializable -@SerialName("LoadStatic") -data class PandaLoadStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadStaticInstIr(this) -} - -@Serializable -@SerialName("LoadObject") -data class PandaLoadObjectInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadObjectInstIr(this) -} - -@Serializable -@SerialName("StoreStatic") -data class PandaStoreStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreStaticInstIr(this) -} - -@Serializable -@SerialName("StoreObject") -data class PandaStoreObjectInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreObjectInstIr(this) -} - -@Serializable -@SerialName("LoadArray") -data class PandaLoadArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadArrayInstIr(this) -} - -@Serializable -@SerialName("StoreArray") -data class PandaStoreArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreArrayInstIr(this) -} - -@Serializable -@SerialName("IsInstance") -data class PandaIsInstanceInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaIsInstanceInstIr(this) -} - -@Serializable -@SerialName("CheckCast") -data class PandaCheckCastInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCheckCastInstIr(this) -} - -@Serializable -@SerialName("Bitcast") -data class PandaBitcastInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaBitcastInstIr(this) -} - -@Serializable -@SerialName("Cast") -data class PandaCastInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCastInstIr(this) -} - -@Serializable -@SerialName("IfImm") -data class PandaIfImmInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val operator: String, - override val operandsType: String, - val immediate: ULong, -) : PandaComparisonInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaIfImmInstIr(this) -} - -@Serializable -@SerialName("Compare") -data class PandaCompareInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val operator: String, - override val operandsType: String, -) : PandaComparisonInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCompareInstIr(this) -} - -@Serializable -@SerialName("Phi") -data class PandaPhiInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val inputBlocks: List, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaPhiInstIr(this) -} - -@Serializable -@SerialName("Add") -data class PandaAddInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAddInstIr(this) -} - -@Serializable -@SerialName("Sub") -data class PandaSubInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSubInstIr(this) -} - -@Serializable -@SerialName("Mul") -data class PandaMulInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaMulInstIr(this) -} - -@Serializable -@SerialName("Div") -data class PandaDivInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaDivInstIr(this) -} - -@Serializable -@SerialName("Mod") -data class PandaModInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaModInstIr(this) -} - -@Serializable -@SerialName("And") -data class PandaAndInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAndInstIr(this) -} - -@Serializable -@SerialName("Or") -data class PandaOrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaOrInstIr(this) -} - -@Serializable -@SerialName("Xor") -data class PandaXorInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaXorInstIr(this) -} - -@Serializable -@SerialName("Shl") -data class PandaShlInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaShlInstIr(this) -} - -@Serializable -@SerialName("Shr") -data class PandaShrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaShrInstIr(this) -} - -@Serializable -@SerialName("AShl") -data class PandaAShlInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAShlInstIr(this) -} - -@Serializable -@SerialName("AShr") -data class PandaAShrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAShrInstIr(this) -} - -@Serializable -@SerialName("Cmp") -data class PandaCmpInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val operator: String, - override val operandsType: String, -) : PandaComparisonInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCmpInstIr(this) -} - -@Serializable -@SerialName("Throw") -data class PandaThrowInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String = "", // TODO: remove default value -) : PandaTerminatingInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaThrowInstIr(this) -} - -@Serializable -@SerialName("NegativeCheck") -data class PandaNegativeCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNegativeCheckInstIr(this) -} - -@Serializable -@SerialName("SaveStateDeoptimize") -data class PandaSaveStateDeoptimizeInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSaveStateDeoptimizeInstIr(this) -} - -@Serializable -@SerialName("Neg") -data class PandaNegInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNegInstIr(this) -} - -@Serializable -@SerialName("Not") -data class PandaNotInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNotInstIr(this) -} - -@Serializable -@SerialName("LenArray") -data class PandaLenArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLenArrayInstIr(this) -} - -@Serializable -@SerialName("BoundsCheck") -data class PandaBoundsCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaBoundsCheckInstIr(this) -} - -@Serializable -@SerialName("NullPtr") -data class PandaNullPtrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNullPtrInstIr(this) -} - -@Serializable -@SerialName("LoadUndefined") -data class PandaLoadUndefinedInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadUndefinedInstIr(this) -} - -@Serializable -@SerialName("RefTypeCheck") -data class PandaRefTypeCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaRefTypeCheckInstIr(this) -} - -@Serializable -@SerialName("Try") -data class PandaTryInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val end_bb: Int = 0, // TODO: remove default value -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaTryInstIr(this) -} - -@Serializable -@SerialName("CatchPhi") -data class PandaCatchPhiInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val throwers: List = emptyList(), -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCatchPhiInstIr(this) -} - -@Serializable -@SerialName("Intrinsic") -data class PandaIntrinsicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val intrinsicId: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaIntrinsicInstIr(this) -} - -@Serializable -@SerialName("LoadFromConstantPool") -data class PandaLoadFromConstantPoolInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val isString: Boolean, - val objectType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadFromConstantPoolInstIr(this) -} - -@Serializable -@SerialName("ResolveStatic") -data class PandaResolveStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaResolveStaticInstIr(this) -} - -@Serializable -@SerialName("ResolveVirtual") -data class PandaResolveVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaResolveVirtualInstIr(this) -} - -@Serializable -@SerialName("CallDynamic") -data class PandaCallDynamicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallDynamicInstIr(this) -} - -@Serializable -@SerialName("CallResolvedVirtual") -data class PandaCallResolvedVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallResolvedVirtualInstIr(this) -} - -@Serializable -@SerialName("CallResolvedStatic") -data class PandaCallResolvedStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallResolvedStaticInstIr(this) -} - -@Serializable -@SerialName("FillConstArray") -data class PandaFillConstArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val objectClass: String, - val length: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaFillConstArrayInstIr(this) -} - -@Serializable -@SerialName("Builtin") -data class PandaBuiltinInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val intrinsicId: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaBuiltinInstIr(this) -} - -@Serializable -@SerialName("LoadResolvedObjectField") -data class PandaLoadResolvedObjectFieldInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadResolvedObjectFieldInstIr(this) -} - -@Serializable -@SerialName("LoadResolvedObjectFieldStatic") -data class PandaLoadResolvedObjectFieldStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadResolvedObjectFieldStaticInstIr(this) -} - -@Serializable -@SerialName("StoreResolvedObjectField") -data class PandaStoreResolvedObjectFieldInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreResolvedObjectFieldInstIr(this) -} - -@Serializable -@SerialName("StoreResolvedObjectFieldStatic") -data class PandaStoreResolvedObjectFieldStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreResolvedObjectFieldStaticInstIr(this) -} - -@Serializable -@SerialName("LoadObjectDynamic") -data class PandaLoadObjectDynamicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val accessType: Int, - val accessMode: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadObjectDynamicInstIr(this) -} - -@Serializable -@SerialName("StoreObjectDynamic") -data class PandaStoreObjectDynamicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val accessType: Int, - val accessMode: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreObjectDynamicInstIr(this) -} - -@Serializable -@SerialName("FunctionImmediate") -data class PandaFunctionImmediateInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val funcPtr: Long, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaFunctionImmediateInstIr(this) -} - -@Serializable -@SerialName("HclassCheck") -data class PandaHclassCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val checkIsFunction: Boolean, - val checkFunctionIsNotClassConstructor: Boolean, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaHclassCheckInstIr(this) -} - -@Serializable -@SerialName("LoadObjFromConst") -data class PandaLoadObjFromConstInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val objPtr: Long, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadObjFromConstInstIr(this) -} - -@Serializable -@SerialName("LoadImmediate") -data class PandaLoadImmediateInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val immediateType: Int, - val immediateClass: String? = null, - val method: String? = null, - val constantPool: Long? = null, - val string: String? = null, - val offset: Long? = null, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadImmediateInstIr(this) -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt deleted file mode 100644 index 3d566fdf9..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ir - -interface PandaInstIrVisitor { - fun visitPandaConstantInstIr(inst: PandaConstantInstIr): T - fun visitPandaSafePointInstIr(inst: PandaSafePointInstIr): T - fun visitPandaSaveStateInstIr(inst: PandaSaveStateInstIr): T - fun visitPandaNewObjectInstIr(inst: PandaNewObjectInstIr): T - fun visitPandaNewArrayInstIr(inst: PandaNewArrayInstIr): T - fun visitPandaCallStaticInstIr(inst: PandaCallStaticInstIr): T - fun visitPandaNullCheckInstIr(inst: PandaNullCheckInstIr): T - fun visitPandaZeroCheckInstIr(inst: PandaZeroCheckInstIr): T - fun visitPandaLoadStringInstIr(inst: PandaLoadStringInstIr): T - fun visitPandaLoadTypeInstIr(inst: PandaLoadTypeInstIr): T - fun visitPandaLoadRuntimeClassInstIr(inst: PandaLoadRuntimeClassInstIr): T - fun visitPandaCallVirtualInstIr(inst: PandaCallVirtualInstIr): T - fun visitPandaCallLaunchVirtualInstIr(inst: PandaCallLaunchVirtualInstIr): T - fun visitPandaCallLaunchStaticInstIr(inst: PandaCallLaunchStaticInstIr): T - fun visitPandaLoadAndInitClassInstIr(inst: PandaLoadAndInitClassInstIr): T - fun visitPandaLoadClassInstIr(inst: PandaLoadClassInstIr): T - fun visitPandaInitClassInstIr(inst: PandaInitClassInstIr): T - fun visitPandaReturnVoidInstIr(inst: PandaReturnVoidInstIr): T - fun visitPandaReturnInstIr(inst: PandaReturnInstIr): T - fun visitPandaParameterInstIr(inst: PandaParameterInstIr): T - fun visitPandaLoadStaticInstIr(inst: PandaLoadStaticInstIr): T - fun visitPandaLoadObjectInstIr(inst: PandaLoadObjectInstIr): T - fun visitPandaStoreStaticInstIr(inst: PandaStoreStaticInstIr): T - fun visitPandaStoreObjectInstIr(inst: PandaStoreObjectInstIr): T - fun visitPandaLoadArrayInstIr(inst: PandaLoadArrayInstIr): T - fun visitPandaStoreArrayInstIr(inst: PandaStoreArrayInstIr): T - fun visitPandaIsInstanceInstIr(inst: PandaIsInstanceInstIr): T - fun visitPandaCheckCastInstIr(inst: PandaCheckCastInstIr): T - fun visitPandaBitcastInstIr(inst: PandaBitcastInstIr): T - fun visitPandaCastInstIr(inst: PandaCastInstIr): T - fun visitPandaIfImmInstIr(inst: PandaIfImmInstIr): T - fun visitPandaCompareInstIr(inst: PandaCompareInstIr): T - fun visitPandaPhiInstIr(inst: PandaPhiInstIr): T - fun visitPandaAddInstIr(inst: PandaAddInstIr): T - fun visitPandaSubInstIr(inst: PandaSubInstIr): T - fun visitPandaMulInstIr(inst: PandaMulInstIr): T - fun visitPandaDivInstIr(inst: PandaDivInstIr): T - fun visitPandaModInstIr(inst: PandaModInstIr): T - fun visitPandaAndInstIr(inst: PandaAndInstIr): T - fun visitPandaOrInstIr(inst: PandaOrInstIr): T - fun visitPandaXorInstIr(inst: PandaXorInstIr): T - fun visitPandaShlInstIr(inst: PandaShlInstIr): T - fun visitPandaShrInstIr(inst: PandaShrInstIr): T - fun visitPandaAShlInstIr(inst: PandaAShlInstIr): T - fun visitPandaAShrInstIr(inst: PandaAShrInstIr): T - fun visitPandaCmpInstIr(inst: PandaCmpInstIr): T - fun visitPandaThrowInstIr(inst: PandaThrowInstIr): T - fun visitPandaNegativeCheckInstIr(inst: PandaNegativeCheckInstIr): T - fun visitPandaSaveStateDeoptimizeInstIr(inst: PandaSaveStateDeoptimizeInstIr): T - fun visitPandaNegInstIr(inst: PandaNegInstIr): T - fun visitPandaNotInstIr(inst: PandaNotInstIr): T - fun visitPandaLenArrayInstIr(inst: PandaLenArrayInstIr): T - fun visitPandaBoundsCheckInstIr(inst: PandaBoundsCheckInstIr): T - fun visitPandaNullPtrInstIr(inst: PandaNullPtrInstIr): T - fun visitPandaLoadUndefinedInstIr(inst: PandaLoadUndefinedInstIr): T - fun visitPandaRefTypeCheckInstIr(inst: PandaRefTypeCheckInstIr): T - fun visitPandaTryInstIr(inst: PandaTryInstIr): T - fun visitPandaCatchPhiInstIr(inst: PandaCatchPhiInstIr): T - fun visitPandaIntrinsicInstIr(inst: PandaIntrinsicInstIr): T - fun visitPandaLoadFromConstantPoolInstIr(inst: PandaLoadFromConstantPoolInstIr): T - fun visitPandaResolveStaticInstIr(inst: PandaResolveStaticInstIr): T - fun visitPandaResolveVirtualInstIr(inst: PandaResolveVirtualInstIr): T - fun visitPandaCallDynamicInstIr(inst: PandaCallDynamicInstIr): T - fun visitPandaCallResolvedVirtualInstIr(inst: PandaCallResolvedVirtualInstIr): T - fun visitPandaCallResolvedStaticInstIr(inst: PandaCallResolvedStaticInstIr): T - fun visitPandaFillConstArrayInstIr(inst: PandaFillConstArrayInstIr): T - fun visitPandaBuiltinInstIr(inst: PandaBuiltinInstIr): T - fun visitPandaLoadResolvedObjectFieldInstIr(inst: PandaLoadResolvedObjectFieldInstIr): T - fun visitPandaLoadResolvedObjectFieldStaticInstIr(inst: PandaLoadResolvedObjectFieldStaticInstIr): T - fun visitPandaStoreResolvedObjectFieldInstIr(inst: PandaStoreResolvedObjectFieldInstIr): T - fun visitPandaStoreResolvedObjectFieldStaticInstIr(inst: PandaStoreResolvedObjectFieldStaticInstIr): T - fun visitPandaLoadObjectDynamicInstIr(inst: PandaLoadObjectDynamicInstIr): T - fun visitPandaStoreObjectDynamicInstIr(inst: PandaStoreObjectDynamicInstIr): T - fun visitPandaFunctionImmediateInstIr(inst: PandaFunctionImmediateInstIr): T - fun visitPandaHclassCheckInstIr(inst: PandaHclassCheckInstIr): T - fun visitPandaLoadObjFromConstInstIr(inst: PandaLoadObjFromConstInstIr): T - fun visitPandaLoadImmediateInstIr(inst: PandaLoadImmediateInstIr): T -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt deleted file mode 100644 index 1e645fb26..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ir - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream -import org.jacodb.panda.staticvm.classpath.AccessFlags -import org.jacodb.panda.staticvm.classpath.PandaClass -import org.jacodb.panda.staticvm.classpath.PandaField -import org.jacodb.panda.staticvm.classpath.PandaInterface -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.classpath.PandaType -import org.jacodb.panda.staticvm.utils.OneDirectionGraph -import org.jacodb.panda.staticvm.utils.applyFold -import org.jacodb.panda.staticvm.utils.inTopsortOrder -import java.io.File -import java.io.InputStream -import java.nio.file.Path -import kotlin.io.path.inputStream - -@Serializable -data class PandaProgramIr( - val classes: List = emptyList(), -) { - companion object { - val json = Json { - // ignoreUnknownKeys = true - classDiscriminator = "opcode" - } - - fun fromJson(jsonString: String): PandaProgramIr { - return json.decodeFromString(jsonString) - } - - @OptIn(ExperimentalSerializationApi::class) - fun from(inputStream: InputStream): PandaProgramIr { - return json.decodeFromStream(inputStream) - } - - fun from(file: File): PandaProgramIr { - return from(file.inputStream().buffered()) - } - - fun from(path: Path): PandaProgramIr { - return from(path.inputStream().buffered()) - } - } - - fun addClassesHierarchyToPandaClasspath(project: PandaProject) { - val classesMap = classes - .filterNot { AccessFlags(it.accessFlags).isInterface } - .associateBy { it.name } - - val graph = OneDirectionGraph(classesMap.values) { - setOfNotNull(it.superClass?.let(classesMap::get)) - } - - requireNotNull(graph.inTopsortOrder()) { - "Found cyclic inheritance" - }.reversed().applyFold(project) { - val superClass = it.superClass?.let { superClassName -> - requireNotNull(findClassOrNull(superClassName)) - } - val interfaces = it.interfaces.mapTo(hashSetOf()) { interfaceName -> - requireNotNull(findInterfaceOrNull(interfaceName)) - } - val pandaClass = PandaClass( - project = this, - name = it.name, - directSuperClass = superClass, - directSuperInterfaces = interfaces, - flags = AccessFlags(it.accessFlags) - ) - addClass(pandaClass) - } - } - - fun addInterfacesHierarchyToPandaClasspath(project: PandaProject) { - val interfacesMap = classes - .filter { AccessFlags(it.accessFlags).isInterface } - .associateBy { it.name } - - val graph = OneDirectionGraph(interfacesMap.values) { - it.interfaces.mapNotNullTo(hashSetOf()) { interfacesMap[it] } - } - - requireNotNull(graph.inTopsortOrder()) { - "Found cyclic inheritance" - }.reversed().applyFold(project) { - val interfaces = it.interfaces.mapTo(hashSetOf()) { interfaceName -> - requireNotNull(findInterfaceOrNull(interfaceName)) - } - val pandaInterface = PandaInterface( - project = this, - name = it.name, - directSuperInterfaces = interfaces, - flags = AccessFlags(it.accessFlags) - ) - addInterface(pandaInterface) - } - } - - fun addFieldsToPandaClasspath(project: PandaProject) { - classes.applyFold(project) { clazz -> - val enclosingClass = requireNotNull(findClassOrInterfaceOrNull(clazz.name)) - clazz.fields.applyFold(this) { field -> - val fieldType = requireNotNull(findTypeOrNull(field.type)) - val pandaField = PandaField( - enclosingClass = enclosingClass, - name = field.name, - type = fieldType, - flags = AccessFlags(field.accessFlags) - ) - addField(pandaField) - } - } - } - - fun addMethodsToPandaClasspath(project: PandaProject) { - classes.applyFold(project) { clazz -> - val enclosingClass = requireNotNull(findClassOrInterfaceOrNull(clazz.name)) - clazz.methods.applyFold(this) { method -> - val returnType = findType(method.returnType) - val isStatic = AccessFlags(method.accessFlags).isStatic - val enclosing: List = if (isStatic) emptyList() else listOf(enclosingClass.type) - val parameters: List = method.parameters.map { requireNotNull(findTypeOrNull(it)) } - val parameterTypes = enclosing + parameters - val pandaMethod = PandaMethod( - signature = method.signature, - name = method.name, - enclosingClass = enclosingClass, - returnType = returnType, - parameterTypes = parameterTypes, - flags = AccessFlags(method.accessFlags) - ) - addMethod(pandaMethod) - } - } - } - - fun addFlowGraphsToPandaClasspath(project: PandaProject) { - classes.applyFold(project) { clazz -> - clazz.methods.applyFold(this) { method -> - val methodNode = requireNotNull(project.findMethod(method.signature)) - if (method.basicBlocks.isNotEmpty()) { - addFlowGraph(methodNode, method.basicBlocks) - } - } - } - } -} - -@Serializable -data class PandaClassIr( - val name: String, - val simpleName: String, - val superClass: String? = null, - val interfaces: List = emptyList(), - val accessFlags: Int = 1, - val fields: List = emptyList(), - val methods: List = emptyList(), -) - -@Serializable -data class PandaFieldIr( - val name: String, - val type: String, - val accessFlags: Int, -) - -@Serializable -data class PandaMethodIr( - val name: String, - val signature: String, - val returnType: String, - val parameters: List = emptyList(), - val accessFlags: Int, - val basicBlocks: List = emptyList(), -) - -@Serializable -data class PandaBasicBlockIr( - val id: Int, - val predecessors: List = emptyList(), - val successors: List = emptyList(), - val insts: List = emptyList(), - val isCatchBegin: Boolean = false, - val isTryBegin: Boolean = false, - val isTryEnd: Boolean = false, - private val handlerIds: List = emptyList(), - private val handledTypes: List = emptyList(), -) { - data class Handler(val id: Int, val type: String?) - - val handlers: List - get() = handlerIds.zip(handledTypes) { id, type -> Handler(id, if (type == "finally") null else type) } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt deleted file mode 100644 index 5a6cb9212..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.ir - -import java.io.File -import java.nio.file.Path -import kotlin.io.path.writeText - -fun PandaProgramIr.toDot(): String { - val lines: MutableList = mutableListOf() - lines += "digraph {" - lines += " rankdir=LR;" - lines += " compound=true;" - - val classes = this.classes - .filterNot { it.name.startsWith("std.") } - .filterNot { it.name.startsWith("escompat.") } - .filterNot { it.name.startsWith("FunctionalInterface") } - - // Classes with properties: - classes.forEach { clazz -> - // CLASS - run { - val labelLines: MutableList = mutableListOf() - labelLines += clazz.name - labelLines += "Fields: (${clazz.fields.size})" - for (field in clazz.fields) { - labelLines += " ${field.name}: ${field.type}" - } - labelLines += "Methods: (${clazz.methods.size})" - for (method in clazz.methods) { - labelLines += " ${method.name}: ${method.returnType}" - } - lines += "" - lines += " \"${clazz.name}\" [shape=rectangle,label=\"${ - labelLines.joinToString("") { "$it\\l" } - }\"]" - } - - // Methods inside class: - clazz.methods.forEach { method -> - // METHOD - lines += " \"${clazz.name}.${method.name}\" [shape=diamond,label=\"${clazz.name}::${method.name}\"];" - lines += " \"${clazz.name}\" -> \"${clazz.name}.${method.name}\"" - } - - // Basic blocks inside method: - clazz.methods.forEach { method -> - // Link to the first basic block inside method: - if (method.basicBlocks.isNotEmpty()) { - lines += " \"${clazz.name}.${method.name}\" -> \"${clazz.name}.${method.name}.bb${method.basicBlocks.first().id}.0\" [lhead=\"${clazz.name}.${method.name}.bb${method.basicBlocks.first().id}\"];" - } - - method.basicBlocks.forEach { bb -> - val last = bb.insts.lastOrNull() - val i = if (bb.insts.isNotEmpty()) bb.insts.lastIndex else 0 - when (last) { - is PandaIfImmInstIr -> { - for ((j, succ) in bb.successors.withIndex()) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" -> \"${clazz.name}.${method.name}.bb${succ}.0\" [lhead=\"${clazz.name}.${method.name}.bb${succ}\", label=\"${if (j == 0) "true" else "false"}\"];" - } - } - - is PandaTryInstIr -> { - for ((j, succ) in bb.successors.withIndex()) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" -> \"${clazz.name}.${method.name}.bb${succ}.0\" [lhead=\"${clazz.name}.${method.name}.bb${succ}\", label=\"${if (j == 0) "try" else "catch"}\"];" - } - } - - else -> { - // check(bb.successors.size <= 1) - for (succ in bb.successors) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" -> \"${clazz.name}.${method.name}.bb${succ}.0\" [lhead=\"${clazz.name}.${method.name}.bb${succ}\"];" - } - } - } - } - - // Basic blocks with instructions: - method.basicBlocks.forEach { bb -> - // BASIC BLOCK - lines += "" - lines += " subgraph \"${clazz.name}.${method.name}.bb${bb.id}\" {" - lines += " cluster=true;" - lines += " label=\"BB ${bb.id}\\nsuccessors = ${bb.successors}\\nisCatchBegin = ${bb.isCatchBegin}\\nisTryBegin = ${bb.isTryBegin}\\nisTryEnd = ${bb.isTryEnd}\";" - - if (bb.insts.isEmpty()) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.0\" [shape=box,label=\"NOP\"];" - } - - // Instructions inside basic block: - bb.insts.forEachIndexed { i, inst -> - val labelLines: MutableList = mutableListOf() - labelLines += "${inst.id}: ${inst.opcode}: ${inst.type}" - if (inst is PandaConstantInstIr) { - labelLines += "value = ${inst.value}" - } - if (inst is PandaLoadStringInstIr) { - labelLines += "string = ${inst.string}" - } - if (inst.inputs.isNotEmpty()) { - labelLines += "inputs = ${inst.inputs}" - } - if (inst.users.isNotEmpty()) { - labelLines += "users = ${inst.users}" - } - if (inst.catchers.isNotEmpty()) { - labelLines += "catchers = ${inst.catchers}" - } - if (inst is PandaCatchPhiInstIr) { - labelLines += "throwers = ${inst.throwers}" - } - // INSTRUCTION - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" [shape=box,label=\"${ - labelLines.joinToString("") { "${it}\\l" } - }\"];" - } - - // Instructions chain: - if (bb.insts.isNotEmpty()) { - lines += " ${ - List(bb.insts.size) { i -> - "\"${clazz.name}.${method.name}.bb${bb.id}.${i}\"" - }.joinToString(" -> ") - };" - } - - lines += " }" - } - } - } - - lines += "}" - return lines.joinToString("\n") -} - -fun PandaProgramIr.dumpDot(file: File) { - file.writeText(toDot()) -} - -fun PandaProgramIr.dumpDot(path: Path) { - path.writeText(toDot()) -} - -fun PandaProgramIr.dumpDot(path: String) { - dumpDot(File(path)) -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt deleted file mode 100644 index 5e8330a18..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.utils - -import org.jacodb.api.common.cfg.Graph - -fun search( - start: T, - successors: (T) -> Iterable, - visitor: (T) -> Unit, -): Set { - val visited = hashSetOf() - fun dfs(node: T) = node.takeIf(visited::add)?.also(visitor)?.let { successors(it).forEach(::dfs) } - dfs(start) - return visited -} - -fun components( - starts: Iterable, - successors: (T) -> Iterable, -): List> { - val visited = hashSetOf() - return starts.mapNotNull { start -> - if (start !in visited) search(start, { successors(it).filter { it !in visited } }, visited::add) - else null - } -} - -fun reachable( - starts: Iterable, - successors: (T) -> Iterable, -): Set = - starts.applyFold(hashSetOf()) { start -> - if (!contains(start)) - addAll(search(start, { successors(it).filterNot(this::contains) }, {})) - } - -fun Graph.rpo(): List { - val visited = hashSetOf() - val order = mutableListOf() - val onStack = hashSetOf() - - fun dfs(node: T) = node.takeIf(visited::add)?.also(onStack::add)?.let { - successors(it).forEach(::dfs) - onStack.remove(it) - order.add(it) - } - - this.forEach { if (it !in visited) dfs(it) } - return order.reversed() -} - -fun Graph.inTopsortOrder(): List? { - val visited = hashSetOf() - val order = mutableListOf() - val stack = hashSetOf() - var foundCycle = false - - fun dfs(node: T) { - if (visited.add(node)) { - stack.add(node) - for (next in successors(node)) { - if (next in stack) { - foundCycle = true - } - dfs(next) - } - stack.remove(node) - order.add(node) - } - } - - val nodes = this.toHashSet() - for (node in nodes) { - dfs(node) - } - return if (foundCycle) null else order.reversed().filter { it in nodes } -} - -fun Graph.SCCs(): OneDirectionGraph> { - val components = components(rpo()) { predecessors(it) } - val colorMap = components.applyFold(hashMapOf>()) { nodes -> - nodes.forEach { put(it, nodes) } - } - return OneDirectionGraph(components) { nodes -> - nodes - .asSequence() - .flatMap { successors(it) } - .map { colorMap[it] } - .requireNoNulls() - .filterNotTo(hashSetOf()) { it == nodes } - } -} - -fun Map.removeNulls(): Map = - entries.filterIsInstance>().associate { (k, v) -> k to v } - -fun Graph.runDP(transition: (T, Map) -> V): Map { - val tsOrder = inTopsortOrder() ?: error("Cannot run DP because of cycle found") - return tsOrder.reversed().applyFold(hashMapOf()) { v -> - put(v, transition.invoke(v, successors(v).associateWith(this::get).removeNulls())) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt deleted file mode 100644 index b6e7859a0..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.utils - -import org.jacodb.panda.staticvm.cfg.PandaGraph -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.cfg.findDominators -import java.util.ArrayDeque -import kotlin.LazyThreadSafetyMode.PUBLICATION - -class PandaLoop( - val graph: PandaGraph, - val head: PandaInst, - val instructions: List, -) { - val exits: Collection by lazy(PUBLICATION) { - val result = hashSetOf() - for (s in instructions) { - graph.successors(s).forEach { - if (!instructions.contains(it)) { - result.add(s) - } - } - } - result - } - - val backJump: PandaInst get() = instructions.last() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as PandaLoop - - if (head != other.head) return false - if (instructions != other.instructions) return false - - return true - } - - override fun hashCode(): Int { - var result = head.hashCode() - result = 31 * result + instructions.hashCode() - return result - } -} - -val PandaGraph.loops: Set - get() { - val finder = findDominators() - val loops = HashMap>() - instructions.forEach { inst -> - val dominators = finder.dominators(inst) - - val headers = arrayListOf() - successors(inst).forEach { - if (dominators.contains(it)) { - headers.add(it) - } - } - headers.forEach { header -> - val loopBody = loopBodyOf(header, inst) - loops[header] = loops[header]?.union(loopBody) ?: loopBody - } - } - return loops.map { (key, value) -> - newLoop(key, value) - }.toSet() - } - -private fun PandaGraph.newLoop(head: PandaInst, loopStatements: MutableList): PandaLoop { - // put header to the top - loopStatements.remove(head) - loopStatements.add(0, head) - - // last statement - val backJump = loopStatements.last() - // must branch back to the head - assert(successors(backJump).contains(head)) - return PandaLoop(this, head = head, instructions = loopStatements) -} - -private fun PandaGraph.loopBodyOf(header: PandaInst, inst: PandaInst): MutableList { - val loopBody = arrayListOf(header) - val stack = ArrayDeque().also { - it.push(inst) - } - while (!stack.isEmpty()) { - val next = stack.pop() - if (!loopBody.contains(next)) { - loopBody.add(0, next) - predecessors(next).forEach { stack.push(it) } - } - } - assert(inst === header && loopBody.size == 1 || loopBody[loopBody.size - 2] === inst) - assert(loopBody[loopBody.size - 1] === header) - return loopBody -} - -private fun MutableList.union(another: List): MutableList = apply { - addAll(another.filter { !contains(it) }) -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt deleted file mode 100644 index e19a4cf07..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.utils - -import org.jacodb.api.common.cfg.Graph - -class OneDirectionGraph( - val nodes: Collection, - val successorsGetter: (T) -> Collection, -) : Graph, Collection by nodes.toSet() { - private val successorsMap = hashMapOf>() - - override fun successors(node: T): Set = if (node in nodes) { - successorsMap.getOrPut(node) { successorsGetter(node).toSet() } - } else { - emptySet() - } - - private val predecessorsMap: Map> by lazy { - nodes.applyFold(hashMapOf>()) { - successors(it) - .also { vs -> check(this@OneDirectionGraph.containsAll(vs)) { "Cannot reverse non-closed relation" } } - .map { v -> getOrPut(v) { hashSetOf() }.add(it) } - } - } - - override fun predecessors(node: T) = reversed.successors(node) - - val reversed: OneDirectionGraph by lazy { - OneDirectionGraph(nodes) { predecessorsMap[it].orEmpty() } - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt deleted file mode 100644 index ac4327668..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jacodb.panda.staticvm.utils - -import org.jacodb.panda.staticvm.cfg.PandaCallExpr -import org.jacodb.panda.staticvm.cfg.PandaInst - -/** - * Applies [operation] to [initial] object with all arguments from [Iterable] consecutively - */ -fun Iterable.applyFold(initial: A, operation: A.(T) -> Unit) = - fold(initial) { acc, elem -> acc.apply { operation(elem) } } - -val PandaInst.callExpr: PandaCallExpr? - get() = operands.filterIsInstance().firstOrNull() diff --git a/jacodb-panda-static/src/main/resources/intrinsics.json b/jacodb-panda-static/src/main/resources/intrinsics.json deleted file mode 100644 index 26db08002..000000000 --- a/jacodb-panda-static/src/main/resources/intrinsics.json +++ /dev/null @@ -1,1892 +0,0 @@ -[ - { - "intrinsicId": "MathAbsI32", - "className": "Math", - "methodName": "absI32" - }, - { - "intrinsicId": "MathAbsI64", - "className": "Math", - "methodName": "absI64" - }, - { - "intrinsicId": "MathAbsF32", - "className": "Math", - "methodName": "absF32" - }, - { - "intrinsicId": "MathAbsF64", - "className": "Math", - "methodName": "absF64" - }, - { - "intrinsicId": "MathMinI32", - "className": "Math", - "methodName": "minI32" - }, - { - "intrinsicId": "MathMinI64", - "className": "Math", - "methodName": "minI64" - }, - { - "intrinsicId": "MathMinF32", - "className": "Math", - "methodName": "minF32" - }, - { - "intrinsicId": "MathMinF64", - "className": "Math", - "methodName": "minF64" - }, - { - "intrinsicId": "MathMaxI32", - "className": "Math", - "methodName": "maxI32" - }, - { - "intrinsicId": "MathMaxI64", - "className": "Math", - "methodName": "maxI64" - }, - { - "intrinsicId": "MathMaxF32", - "className": "Math", - "methodName": "maxF32" - }, - { - "intrinsicId": "MathMaxF64", - "className": "Math", - "methodName": "maxF64" - }, - { - "intrinsicId": "DoubleIsInf", - "className": "Double", - "methodName": "isInfinite" - }, - { - "intrinsicId": "FloatIsInf", - "className": "Float", - "methodName": "isInfinite" - }, - { - "intrinsicId": "MathSinF32", - "className": "Math", - "methodName": "fsin" - }, - { - "intrinsicId": "MathSinF64", - "className": "Math", - "methodName": "sin" - }, - { - "intrinsicId": "MathCosF32", - "className": "Math", - "methodName": "fcos" - }, - { - "intrinsicId": "MathCosF64", - "className": "Math", - "methodName": "cos" - }, - { - "intrinsicId": "MathPowF32", - "className": "Math", - "methodName": "fpow" - }, - { - "intrinsicId": "MathPowF64", - "className": "Math", - "methodName": "pow" - }, - { - "intrinsicId": "MathSqrtF32", - "className": "Math", - "methodName": "fsqrt" - }, - { - "intrinsicId": "MathSqrtF64", - "className": "Math", - "methodName": "sqrt" - }, - { - "intrinsicId": "MathCalculateDouble", - "className": "Math", - "methodName": "calculateDouble" - }, - { - "intrinsicId": "MathCalculateFloat", - "className": "Math", - "methodName": "calculateFloat" - }, - { - "intrinsicId": "IOPrintString", - "className": "IO", - "methodName": "printString" - }, - { - "intrinsicId": "IOPrintF32", - "className": "IO", - "methodName": "printF32" - }, - { - "intrinsicId": "IOPrintF64", - "className": "IO", - "methodName": "printF64" - }, - { - "intrinsicId": "IOPrintI32", - "className": "IO", - "methodName": "printI32" - }, - { - "intrinsicId": "IOPrintU32", - "className": "IO", - "methodName": "printU32" - }, - { - "intrinsicId": "IOPrintI64", - "className": "IO", - "methodName": "printI64" - }, - { - "intrinsicId": "IOPrintU64", - "className": "IO", - "methodName": "printU64" - }, - { - "intrinsicId": "SystemCompileMethod", - "className": "System", - "methodName": "compileMethod" - }, - { - "intrinsicId": "SystemExit", - "className": "System", - "methodName": "exit" - }, - { - "intrinsicId": "SystemNanoTime", - "className": "System", - "methodName": "nanoTime" - }, - { - "intrinsicId": "SystemAssert", - "className": "System", - "methodName": "assert" - }, - { - "intrinsicId": "SystemAssertPrint", - "className": "System", - "methodName": "assertPrint" - }, - { - "intrinsicId": "SystemScheduleCoroutine", - "className": "System", - "methodName": "scheduleCoroutine" - }, - { - "intrinsicId": "SystemCoroutineGetWorkerId", - "className": "System", - "methodName": "getCoroutineWorkerId" - }, - { - "intrinsicId": "CheckTag", - "className": "DebugUtils", - "methodName": "checkTag" - }, - { - "intrinsicId": "ConvertStringToI32", - "className": "Convert", - "methodName": "stringToI32" - }, - { - "intrinsicId": "ConvertStringToU32", - "className": "Convert", - "methodName": "stringToU32" - }, - { - "intrinsicId": "ConvertStringToI64", - "className": "Convert", - "methodName": "stringToI64" - }, - { - "intrinsicId": "ConvertStringToU64", - "className": "Convert", - "methodName": "stringToU64" - }, - { - "intrinsicId": "ConvertStringToF32", - "className": "Convert", - "methodName": "stringToF32" - }, - { - "intrinsicId": "ConvertStringToF64", - "className": "Convert", - "methodName": "stringToF64" - }, - { - "intrinsicId": "ObjectCreateNonMovable", - "className": "Object", - "methodName": "createNonMovable" - }, - { - "intrinsicId": "ObjectMonitorEnter", - "className": "Object", - "methodName": "monitorEnter" - }, - { - "intrinsicId": "ObjectMonitorExit", - "className": "Object", - "methodName": "monitorExit" - }, - { - "intrinsicId": "ObjectWait", - "className": "Object", - "methodName": "Wait" - }, - { - "intrinsicId": "ObjectTimedWait", - "className": "Object", - "methodName": "TimedWait" - }, - { - "intrinsicId": "ObjectTimedWaitNanos", - "className": "Object", - "methodName": "TimedWaitNanos" - }, - { - "intrinsicId": "ObjectNotify", - "className": "Object", - "methodName": "Notify" - }, - { - "intrinsicId": "ObjectNotifyAll", - "className": "Object", - "methodName": "NotifyAll" - }, - { - "intrinsicId": "SlowPathEntry", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "SaveRegistersEp", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "RestoreRegistersEp", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "Unreachable", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "TailCall", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "InterpreterReturn", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "LoadAcquireMarkWordExclusive", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "StoreReleaseMarkWordExclusive", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "CompareAndSetMarkWord", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "DataMemoryBarrierFull", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "CompressEightUtf16ToUtf8CharsUsingSimd", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "CompressSixteenUtf16ToUtf8CharsUsingSimd", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "StdMathSin", - "className": "std.math.ETSGLOBAL", - "methodName": "sin" - }, - { - "intrinsicId": "StdMathCos", - "className": "std.math.ETSGLOBAL", - "methodName": "cos" - }, - { - "intrinsicId": "StdMathPower", - "className": "std.math.ETSGLOBAL", - "methodName": "power" - }, - { - "intrinsicId": "StdMathSqrt", - "className": "std.math.ETSGLOBAL", - "methodName": "sqrt" - }, - { - "intrinsicId": "StdMathAbs", - "className": "std.math.ETSGLOBAL", - "methodName": "abs" - }, - { - "intrinsicId": "StdMathMaxI32", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMaxI64", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMaxF32", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMaxF64", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMinI32", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathMinI64", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathMinF32", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathMinF64", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathRandom", - "className": "std.math.ETSGLOBAL", - "methodName": "random" - }, - { - "intrinsicId": "StdMathAcos", - "className": "std.math.ETSGLOBAL", - "methodName": "acos" - }, - { - "intrinsicId": "StdMathAcosh", - "className": "std.math.ETSGLOBAL", - "methodName": "acosh" - }, - { - "intrinsicId": "StdMathAsin", - "className": "std.math.ETSGLOBAL", - "methodName": "asin" - }, - { - "intrinsicId": "StdMathAsinh", - "className": "std.math.ETSGLOBAL", - "methodName": "asinh" - }, - { - "intrinsicId": "StdMathAtan2", - "className": "std.math.ETSGLOBAL", - "methodName": "atan2" - }, - { - "intrinsicId": "StdMathAtanh", - "className": "std.math.ETSGLOBAL", - "methodName": "atanh" - }, - { - "intrinsicId": "StdMathAtan", - "className": "std.math.ETSGLOBAL", - "methodName": "atan" - }, - { - "intrinsicId": "StdMathSinh", - "className": "std.math.ETSGLOBAL", - "methodName": "sinh" - }, - { - "intrinsicId": "StdMathCosh", - "className": "std.math.ETSGLOBAL", - "methodName": "cosh" - }, - { - "intrinsicId": "StdMathFloor", - "className": "std.math.ETSGLOBAL", - "methodName": "floor" - }, - { - "intrinsicId": "StdMathRound", - "className": "std.math.ETSGLOBAL", - "methodName": "round" - }, - { - "intrinsicId": "StdMathTrunc", - "className": "std.math.ETSGLOBAL", - "methodName": "trunc" - }, - { - "intrinsicId": "StdMathCbrt", - "className": "std.math.ETSGLOBAL", - "methodName": "cbrt" - }, - { - "intrinsicId": "StdMathTan", - "className": "std.math.ETSGLOBAL", - "methodName": "tan" - }, - { - "intrinsicId": "StdMathTanh", - "className": "std.math.ETSGLOBAL", - "methodName": "tanh" - }, - { - "intrinsicId": "StdMathExp", - "className": "std.math.ETSGLOBAL", - "methodName": "exp" - }, - { - "intrinsicId": "StdMathLog10", - "className": "std.math.ETSGLOBAL", - "methodName": "log10" - }, - { - "intrinsicId": "StdMathExpm1", - "className": "std.math.ETSGLOBAL", - "methodName": "expm1" - }, - { - "intrinsicId": "StdMathCeil", - "className": "std.math.ETSGLOBAL", - "methodName": "ceil" - }, - { - "intrinsicId": "StdMathLog", - "className": "std.math.ETSGLOBAL", - "methodName": "log" - }, - { - "intrinsicId": "StdMathRem", - "className": "std.math.ETSGLOBAL", - "methodName": "rem" - }, - { - "intrinsicId": "StdMathMod", - "className": "std.math.ETSGLOBAL", - "methodName": "mod" - }, - { - "intrinsicId": "StdMathClz64", - "className": "std.math.ETSGLOBAL", - "methodName": "clz64" - }, - { - "intrinsicId": "StdMathClz32", - "className": "std.math.ETSGLOBAL", - "methodName": "clz32" - }, - { - "intrinsicId": "StdMathClz32Double", - "className": "std.math.ETSGLOBAL", - "methodName": "clz32Double" - }, - { - "intrinsicId": "StdMathSignbit", - "className": "std.math.ETSGLOBAL", - "methodName": "signbit" - }, - { - "intrinsicId": "StdMathImul", - "className": "std.math.ETSGLOBAL", - "methodName": "imul" - }, - { - "intrinsicId": "StdMathFround", - "className": "std.math.ETSGLOBAL", - "methodName": "fround" - }, - { - "intrinsicId": "StdConsolePrintString", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintU1", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI8", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI16", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintU16", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI32", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI64", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintln", - "className": "std.core.Console", - "methodName": "println" - }, - { - "intrinsicId": "StdCoreLoadLibrary", - "className": "std.core.ETSGLOBAL", - "methodName": "loadLibrary" - }, - { - "intrinsicId": "StdCoreStringGetChars", - "className": "std.core.String", - "methodName": "getChars" - }, - { - "intrinsicId": "StdCoreStringGetLength", - "className": "std.core.String", - "methodName": "getLength" - }, - { - "intrinsicId": "StdCoreStringLength", - "className": "std.core.String", - "methodName": "length" - }, - { - "intrinsicId": "StdCoreStringIsEmpty", - "className": "std.core.String", - "methodName": "isEmpty" - }, - { - "intrinsicId": "StdCoreStringCharAt", - "className": "std.core.String", - "methodName": "charAt" - }, - { - "intrinsicId": "StdCoreStringEquals", - "className": "std.core.String", - "methodName": "equals" - }, - { - "intrinsicId": "StdCoreStringLocaleCmp", - "className": "std.core.String", - "methodName": "localeCompare" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFC", - "className": "std.core.String", - "methodName": "normalizeNFC" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFD", - "className": "std.core.String", - "methodName": "normalizeNFD" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFKC", - "className": "std.core.String", - "methodName": "normalizeNFKC" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFKD", - "className": "std.core.String", - "methodName": "normalizeNFKD" - }, - { - "intrinsicId": "StdCoreStringToLowerCase", - "className": "std.core.String", - "methodName": "toLowerCase" - }, - { - "intrinsicId": "StdCoreStringToUpperCase", - "className": "std.core.String", - "methodName": "toUpperCase" - }, - { - "intrinsicId": "StdCoreStringToLocaleLowerCase", - "className": "std.core.String", - "methodName": "toLocaleLowerCase" - }, - { - "intrinsicId": "StdCoreStringToLocaleUpperCase", - "className": "std.core.String", - "methodName": "toLocaleUpperCase" - }, - { - "intrinsicId": "StdCoreStringIsWellFormed", - "className": "std.core.String", - "methodName": "isWellFormed" - }, - { - "intrinsicId": "StdCoreStringIndexOf", - "className": "std.core.String", - "methodName": "indexOf" - }, - { - "intrinsicId": "StdCoreStringIndexOfAfter", - "className": "std.core.String", - "methodName": "indexOf" - }, - { - "intrinsicId": "StdCoreStringIndexOfString", - "className": "std.core.String", - "methodName": "indexOf" - }, - { - "intrinsicId": "StdCoreStringLastIndexOfString", - "className": "std.core.String", - "methodName": "lastIndexOf" - }, - { - "intrinsicId": "StdCoreStringSubstring", - "className": "std.core.String", - "methodName": "substring" - }, - { - "intrinsicId": "StdCoreStringCodePointToChar", - "className": "std.core.String", - "methodName": "codePointToChar" - }, - { - "intrinsicId": "StdCoreStringHashCode", - "className": "std.core.String", - "methodName": "$_hashCode" - }, - { - "intrinsicId": "StdCoreStringIsCompressed", - "className": "std.core.String", - "methodName": "isCompressed" - }, - { - "intrinsicId": "StdCoreStringBuilderConcatStrings", - "className": "std.core.StringBuilder", - "methodName": "concatStrings" - }, - { - "intrinsicId": "StdCoreToStringBoolean", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringByte", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringChar", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringShort", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringInt", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringLong", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreSbAppendFloat", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendDouble", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendLong", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendInt", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendShort", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendByte", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendChar", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendBool", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendString", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbToString", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "EscompatDateNow", - "className": "escompat.Date", - "methodName": "now" - }, - { - "intrinsicId": "EscompatDateGetLocalTimezoneOffset", - "className": "escompat.Date", - "methodName": "getLocalTimezoneOffset" - }, - { - "intrinsicId": "EscompatDateGetTimezoneName", - "className": "escompat.Date", - "methodName": "getTimezoneName" - }, - { - "intrinsicId": "EscompatDateGetLocaleString", - "className": "escompat.Date", - "methodName": "getLocaleString" - }, - { - "intrinsicId": "EscompatArrayBufferFrom", - "className": "escompat.ArrayBuffer", - "methodName": "from" - }, - { - "intrinsicId": "StdTimeDateNanoNow", - "className": "std.time.Chrono", - "methodName": "nanoNow" - }, - { - "intrinsicId": "StdFloatToString", - "className": "std.core.Float", - "methodName": "toString" - }, - { - "intrinsicId": "StdFloatIsNan", - "className": "std.core.Float", - "methodName": "isNaN" - }, - { - "intrinsicId": "StdFloatIsFinite", - "className": "std.core.Float", - "methodName": "isFinite" - }, - { - "intrinsicId": "StdFloatBitCastFromInt", - "className": "std.core.Float", - "methodName": "bitCastFromInt" - }, - { - "intrinsicId": "StdFloatBitCastToInt", - "className": "std.core.Float", - "methodName": "bitCastToInt" - }, - { - "intrinsicId": "StdFloatIsInteger", - "className": "std.core.Float", - "methodName": "isInteger" - }, - { - "intrinsicId": "StdFloatIsSafeInteger", - "className": "std.core.Float", - "methodName": "isSafeInteger" - }, - { - "intrinsicId": "StdDoubleToString", - "className": "std.core.Double", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreDoubleToLocaleString", - "className": "std.core.Double", - "methodName": "toLocaleString" - }, - { - "intrinsicId": "StdCoreDoubleParseFloat", - "className": "std.core.Double", - "methodName": "parseFloat" - }, - { - "intrinsicId": "StdCoreDoubleParseInt", - "className": "std.core.Double", - "methodName": "parseIntCore" - }, - { - "intrinsicId": "StdCoreDoubleToExponential", - "className": "std.core.Double", - "methodName": "toExponential" - }, - { - "intrinsicId": "StdCoreDoubleToPrecision", - "className": "std.core.Double", - "methodName": "toPrecision" - }, - { - "intrinsicId": "StdCoreDoubleToFixed", - "className": "std.core.Double", - "methodName": "toFixed" - }, - { - "intrinsicId": "StdCoreDoubleNumberFromString", - "className": "std.core.Double", - "methodName": "numberFromString" - }, - { - "intrinsicId": "StdDoubleIsNan", - "className": "std.core.Double", - "methodName": "isNaN" - }, - { - "intrinsicId": "StdDoubleIsFinite", - "className": "std.core.Double", - "methodName": "isFinite" - }, - { - "intrinsicId": "StdDoubleBitCastFromLong", - "className": "std.core.Double", - "methodName": "bitCastFromLong" - }, - { - "intrinsicId": "StdDoubleBitCastToLong", - "className": "std.core.Double", - "methodName": "bitCastToLong" - }, - { - "intrinsicId": "StdDoubleIsInteger", - "className": "std.core.Double", - "methodName": "isInteger" - }, - { - "intrinsicId": "StdDoubleIsSafeInteger", - "className": "std.core.Double", - "methodName": "isSafeInteger" - }, - { - "intrinsicId": "StdCoreAllocGenericArray", - "className": "std.core.ETSGLOBAL", - "methodName": "__alloc_array" - }, - { - "intrinsicId": "StdCoreBoolCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreCharCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreByteCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreShortCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreIntCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreLongCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreFloatCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreDoubleCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCorePrintStackTrace", - "className": "std.core.ETSGLOBAL", - "methodName": "printStackTrace" - }, - { - "intrinsicId": "StdCoreStackTraceLines", - "className": "std.core.ETSGLOBAL", - "methodName": "stackTraceLines" - }, - { - "intrinsicId": "StdCoreStackTraceProvisionStackTrace", - "className": "std.core.StackTrace", - "methodName": "provisionStackTrace" - }, - { - "intrinsicId": "StdCoreExit", - "className": "std.core.ETSGLOBAL", - "methodName": "exit" - }, - { - "intrinsicId": "StdGCStartGC", - "className": "std.core.GC", - "methodName": "startGCImpl" - }, - { - "intrinsicId": "StdGCWaitForFinishGC", - "className": "std.core.GC", - "methodName": "waitForFinishGC" - }, - { - "intrinsicId": "StdGCScheduleGCAfterNthAlloc", - "className": "std.core.GC", - "methodName": "scheduleGcAfterNthAlloc" - }, - { - "intrinsicId": "StdGCIsScheduledGCTriggered", - "className": "std.core.GC", - "methodName": "isScheduledGCTriggered" - }, - { - "intrinsicId": "StdGCPostponeGCStart", - "className": "std.core.GC", - "methodName": "postponeGCStart" - }, - { - "intrinsicId": "StdGCPostponeGCEnd", - "className": "std.core.GC", - "methodName": "postponeGCEnd" - }, - { - "intrinsicId": "StdGCAllocatePinnedBooleanArray", - "className": "std.core.GC", - "methodName": "allocatePinnedBooleanArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedByteArray", - "className": "std.core.GC", - "methodName": "allocatePinnedByteArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedCharArray", - "className": "std.core.GC", - "methodName": "allocatePinnedCharArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedShortArray", - "className": "std.core.GC", - "methodName": "allocatePinnedShortArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedIntArray", - "className": "std.core.GC", - "methodName": "allocatePinnedIntArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedLongArray", - "className": "std.core.GC", - "methodName": "allocatePinnedLongArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedFloatArray", - "className": "std.core.GC", - "methodName": "allocatePinnedFloatArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedDoubleArray", - "className": "std.core.GC", - "methodName": "allocatePinnedDoubleArray" - }, - { - "intrinsicId": "StdGCGetObjectSpaceType", - "className": "std.core.GC", - "methodName": "getObjectSpaceType" - }, - { - "intrinsicId": "StdGCGetObjectAddress", - "className": "std.core.GC", - "methodName": "getObjectAddress" - }, - { - "intrinsicId": "StdGCPinObject", - "className": "std.core.GC", - "methodName": "pinObject" - }, - { - "intrinsicId": "StdGCUnpinObject", - "className": "std.core.GC", - "methodName": "unpinObject" - }, - { - "intrinsicId": "StdGetFreeHeapSize", - "className": "std.core.GC", - "methodName": "getFreeHeapSize" - }, - { - "intrinsicId": "StdGetUsedHeapSize", - "className": "std.core.GC", - "methodName": "getUsedHeapSize" - }, - { - "intrinsicId": "StdGetReservedHeapSize", - "className": "std.core.GC", - "methodName": "getReservedHeapSize" - }, - { - "intrinsicId": "StdGCRegisterNativeAllocation", - "className": "std.core.GC", - "methodName": "registerNativeAllocation" - }, - { - "intrinsicId": "StdGCRegisterNativeFree", - "className": "std.core.GC", - "methodName": "registerNativeFree" - }, - { - "intrinsicId": "StdFinalizationRegistryRegisterInstance", - "className": "std.core.FinalizationRegistry", - "methodName": "registerInstance" - }, - { - "intrinsicId": "StdPromiseResolve", - "className": "std.core.Promise", - "methodName": "resolveImpl" - }, - { - "intrinsicId": "StdPromiseReject", - "className": "std.core.Promise", - "methodName": "rejectImpl" - }, - { - "intrinsicId": "StdPromiseAddToJobQueue", - "className": "std.core.Promise", - "methodName": "addToJobQueue" - }, - { - "intrinsicId": "StdPromiseAwait", - "className": "std.core.Promise", - "methodName": "awaitResolution" - }, - { - "intrinsicId": "StdCoroutineSchedule", - "className": "std.core.Coroutine", - "methodName": "Schedule" - }, - { - "intrinsicId": "SharedMemoryCreate", - "className": "escompat.SharedMemory", - "methodName": "create" - }, - { - "intrinsicId": "SharedMemoryAddI8", - "className": "escompat.SharedMemory", - "methodName": "atomicAddI8" - }, - { - "intrinsicId": "SharedMemoryAndI8", - "className": "escompat.SharedMemory", - "methodName": "atomicAndI8" - }, - { - "intrinsicId": "SharedMemoryCompareExchangeI8", - "className": "escompat.SharedMemory", - "methodName": "atomicCompareExchangeI8" - }, - { - "intrinsicId": "SharedMemoryExchangeI8", - "className": "escompat.SharedMemory", - "methodName": "atomicExchangeI8" - }, - { - "intrinsicId": "SharedMemoryLoadI8", - "className": "escompat.SharedMemory", - "methodName": "atomicLoadI8" - }, - { - "intrinsicId": "SharedMemoryOrI8", - "className": "escompat.SharedMemory", - "methodName": "atomicOrI8" - }, - { - "intrinsicId": "SharedMemoryStoreI8", - "className": "escompat.SharedMemory", - "methodName": "atomicStoreI8" - }, - { - "intrinsicId": "SharedMemorySubI8", - "className": "escompat.SharedMemory", - "methodName": "atomicSubI8" - }, - { - "intrinsicId": "SharedMemoryXorI8", - "className": "escompat.SharedMemory", - "methodName": "atomicXorI8" - }, - { - "intrinsicId": "SharedMemoryWaitI32", - "className": "escompat.SharedMemory", - "methodName": "atomicWaitI32" - }, - { - "intrinsicId": "SharedMemoryWaitI64", - "className": "escompat.SharedMemory", - "methodName": "atomicWaitI64" - }, - { - "intrinsicId": "SharedMemoryTimedWaitI32", - "className": "escompat.SharedMemory", - "methodName": "atomicTimedWaitI32" - }, - { - "intrinsicId": "SharedMemoryTimedWaitI64", - "className": "escompat.SharedMemory", - "methodName": "atomicTimedWaitI64" - }, - { - "intrinsicId": "SharedMemoryNotify", - "className": "escompat.SharedMemory", - "methodName": "atomicNotify" - }, - { - "intrinsicId": "SharedMemoryBoundedNotify", - "className": "escompat.SharedMemory", - "methodName": "atomicBoundedNotify" - }, - { - "intrinsicId": "StdCoroutineGetWorkerId", - "className": "std.debug.concurrency.CoroutineExtras", - "methodName": "getWorkerId" - }, - { - "intrinsicId": "StdCoroutineSetSchedulingPolicy", - "className": "std.debug.concurrency.CoroutineExtras", - "methodName": "setSchedulingPolicy" - }, - { - "intrinsicId": "StdAtomicFlagSet", - "className": "std.debug.concurrency.AtomicFlag", - "methodName": "set" - }, - { - "intrinsicId": "StdAtomicFlagGet", - "className": "std.debug.concurrency.AtomicFlag", - "methodName": "get" - }, - { - "intrinsicId": "StdRuntimeGetPlatformIsLittleEndian", - "className": "escompat.ETSGLOBAL", - "methodName": "RuntimeGetPlatformIsLittleEndian" - }, - { - "intrinsicId": "StdCoreRuntimeIsSameReference", - "className": "std.core.Runtime", - "methodName": "isSameReference" - }, - { - "intrinsicId": "StdRuntimeGetHashCode", - "className": "std.core.Runtime", - "methodName": "getHashCode" - }, - { - "intrinsicId": "StdCoreRuntimeFailedTypeCastException", - "className": "std.core.Runtime", - "methodName": "failedTypeCastException" - }, - { - "intrinsicId": "StdCoreRuntimeTypeof", - "className": "std.core.Runtime", - "methodName": "typeOf" - }, - { - "intrinsicId": "escompatJSONStringifyObj", - "className": "escompat.JSON", - "methodName": "stringifyObj" - }, - { - "intrinsicId": "EscompatRegExpCompile", - "className": "escompat.RegExp", - "methodName": "compile" - }, - { - "intrinsicId": "EscompatRegExpExec", - "className": "escompat.RegExp", - "methodName": "execImpl" - }, - { - "intrinsicId": "TypeAPIGetTypeDescriptor", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeDescriptor" - }, - { - "intrinsicId": "TypeAPIGetTypeKind", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeKind" - }, - { - "intrinsicId": "TypeAPIIsValueType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIIsValueType" - }, - { - "intrinsicId": "TypeAPIGetTypeName", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeName" - }, - { - "intrinsicId": "TypeAPIGetClassAttributes", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetClassAttributes" - }, - { - "intrinsicId": "TypeAPIGetFieldsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetFieldsNum" - }, - { - "intrinsicId": "TypeAPIGetOwnFieldsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetOwnFieldsNum" - }, - { - "intrinsicId": "TypeAPIGetField", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetField" - }, - { - "intrinsicId": "TypeAPIGetOwnField", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetOwnField" - }, - { - "intrinsicId": "TypeAPIGetFieldByName", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetFieldByName" - }, - { - "intrinsicId": "TypeAPIGetStaticFieldValue", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetStaticFieldValue" - }, - { - "intrinsicId": "TypeAPIGetMethodsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetMethodsNum" - }, - { - "intrinsicId": "TypeAPIGetMethod", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetMethod" - }, - { - "intrinsicId": "TypeAPIGetConstructorsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetConstructorsNum" - }, - { - "intrinsicId": "TypeAPIGetConstructor", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetConstructor" - }, - { - "intrinsicId": "TypeAPIGetParametersNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetParametersNum" - }, - { - "intrinsicId": "TypeAPIGetParameter", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetParameter" - }, - { - "intrinsicId": "TypeAPIGetTypeId", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeId" - }, - { - "intrinsicId": "TypeAPIGetArrayElementType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetArrayElementType" - }, - { - "intrinsicId": "TypeAPIMakeArrayInstance", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIMakeArrayInstance" - }, - { - "intrinsicId": "TypeAPIGetBaseType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetBaseType" - }, - { - "intrinsicId": "TypeAPIGetInterfacesNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetInterfacesNum" - }, - { - "intrinsicId": "TypeAPIGetInterface", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetInterface" - }, - { - "intrinsicId": "TypeAPISetStaticFieldValue", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPISetStaticFieldValue" - }, - { - "intrinsicId": "TypeAPIIsInheritedFrom", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIIsInheritedFrom" - }, - { - "intrinsicId": "TypeAPIGetFunctionAttributes", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetFunctionAttributes" - }, - { - "intrinsicId": "TypeAPIGetResultType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetResultType" - }, - { - "intrinsicId": "StdMethodInvoke", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIMethodInvoke" - }, - { - "intrinsicId": "StdMethodInvokeConstructor", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIMethodInvokeConstructor" - }, - { - "intrinsicId": "TypeAPIGetReceiverType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetReceiverType" - }, - { - "intrinsicId": "StdCoreCharIsUpperCase", - "className": "std.core.Char", - "methodName": "isUpperCase" - }, - { - "intrinsicId": "StdCoreCharToUpperCase", - "className": "std.core.Char", - "methodName": "toUpperCase" - }, - { - "intrinsicId": "StdCoreCharIsLowerCase", - "className": "std.core.Char", - "methodName": "isLowerCase" - }, - { - "intrinsicId": "StdCoreCharToLowerCase", - "className": "std.core.Char", - "methodName": "toLowerCase" - }, - { - "intrinsicId": "ValueAPIGetFieldObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldObject" - }, - { - "intrinsicId": "ValueAPIGetFieldBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldBoolean" - }, - { - "intrinsicId": "ValueAPIGetFieldByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByte" - }, - { - "intrinsicId": "ValueAPIGetFieldChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldChar" - }, - { - "intrinsicId": "ValueAPIGetFieldShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldShort" - }, - { - "intrinsicId": "ValueAPIGetFieldInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldInt" - }, - { - "intrinsicId": "ValueAPIGetFieldLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldLong" - }, - { - "intrinsicId": "ValueAPIGetFieldFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldFloat" - }, - { - "intrinsicId": "ValueAPIGetFieldDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldDouble" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameObject" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameBoolean" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameByte" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameChar" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameShort" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameInt" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameLong" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameFloat" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameDouble" - }, - { - "intrinsicId": "ValueAPISetFieldObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldObject" - }, - { - "intrinsicId": "ValueAPISetFieldBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldBoolean" - }, - { - "intrinsicId": "ValueAPISetFieldByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByte" - }, - { - "intrinsicId": "ValueAPISetFieldChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldChar" - }, - { - "intrinsicId": "ValueAPISetFieldShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldShort" - }, - { - "intrinsicId": "ValueAPISetFieldInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldInt" - }, - { - "intrinsicId": "ValueAPISetFieldLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldLong" - }, - { - "intrinsicId": "ValueAPISetFieldFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldFloat" - }, - { - "intrinsicId": "ValueAPISetFieldDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldDouble" - }, - { - "intrinsicId": "ValueAPISetFieldByNameObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameObject" - }, - { - "intrinsicId": "ValueAPISetFieldByNameBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameBoolean" - }, - { - "intrinsicId": "ValueAPISetFieldByNameByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameByte" - }, - { - "intrinsicId": "ValueAPISetFieldByNameChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameChar" - }, - { - "intrinsicId": "ValueAPISetFieldByNameShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameShort" - }, - { - "intrinsicId": "ValueAPISetFieldByNameInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameInt" - }, - { - "intrinsicId": "ValueAPISetFieldByNameLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameLong" - }, - { - "intrinsicId": "ValueAPISetFieldByNameFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameFloat" - }, - { - "intrinsicId": "ValueAPISetFieldByNameDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameDouble" - }, - { - "intrinsicId": "ValueAPIGetArrayLength", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetArrayLength" - }, - { - "intrinsicId": "ValueAPISetElementObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementObject" - }, - { - "intrinsicId": "ValueAPISetElementBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementBoolean" - }, - { - "intrinsicId": "ValueAPISetElementByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementByte" - }, - { - "intrinsicId": "ValueAPISetElementChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementChar" - }, - { - "intrinsicId": "ValueAPISetElementShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementShort" - }, - { - "intrinsicId": "ValueAPISetElementInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementInt" - }, - { - "intrinsicId": "ValueAPISetElementLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementLong" - }, - { - "intrinsicId": "ValueAPISetElementFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementFloat" - }, - { - "intrinsicId": "ValueAPISetElementDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementDouble" - }, - { - "intrinsicId": "ValueAPIGetElementObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementObject" - }, - { - "intrinsicId": "ValueAPIGetElementBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementBoolean" - }, - { - "intrinsicId": "ValueAPIGetElementByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementByte" - }, - { - "intrinsicId": "ValueAPIGetElementChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementChar" - }, - { - "intrinsicId": "ValueAPIGetElementShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementShort" - }, - { - "intrinsicId": "ValueAPIGetElementInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementInt" - }, - { - "intrinsicId": "ValueAPIGetElementLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementLong" - }, - { - "intrinsicId": "ValueAPIGetElementFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementFloat" - }, - { - "intrinsicId": "ValueAPIGetElementDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementDouble" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "createCtx" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxDestroy", - "className": "std.core.TypeCreatorCtx", - "methodName": "destroyCtx" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxCommit", - "className": "std.core.TypeCreatorCtx", - "methodName": "commit" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxGetError", - "className": "std.core.TypeCreatorCtx", - "methodName": "getError" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxGetObjectsArrayForCCtor", - "className": "std.core.TypeCreatorCtx", - "methodName": "getObjectsArrayForCCtor" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxGetTypeDescFromPointer", - "className": "std.core.TypeCreatorCtx", - "methodName": "getTypeDescFromPointer" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "classCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassSetBase", - "className": "std.core.TypeCreatorCtx", - "methodName": "classSetBase" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassAddIface", - "className": "std.core.TypeCreatorCtx", - "methodName": "classAddIface" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassAddField", - "className": "std.core.TypeCreatorCtx", - "methodName": "classAddField" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxInterfaceCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "interfaceCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxInterfaceAddBase", - "className": "std.core.TypeCreatorCtx", - "methodName": "interfaceAddBase" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddAccessMod", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddAccessMod" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddParam", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddParam" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyFromMethod", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyFromMethod" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyFromLambda", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyFromLambda" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyFromErasedLambda", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyFromErasedLambda" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyDefault", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyDefault" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddResult", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddResult" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAdd", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAdd" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeAddParam", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeAddParam" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeAddResult", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeAddResult" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeAdd", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeAdd" - }, - { - "intrinsicId": "CompilerEtsLdObjByNameObj", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameI32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameI64", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameF32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameF64", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameObj", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameI32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameI64", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameF32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameF64", - "className": null, - "methodName": null - } -] diff --git a/jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt b/jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt deleted file mode 100644 index e4bb096b5..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package panda - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintAnalysisOptions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.PandaStaticTraits -import org.jacodb.panda.staticvm.cfg.PandaApplicationGraph -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.junit.jupiter.api.condition.EnabledIf -import kotlin.test.Test -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class PandaDemoCases { - - companion object : PandaStaticTraits - - private fun loadProject(path: String): PandaProject { - val program = loadProgram("/$path") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - return project - } - - private fun stdlibAvailable() = EtsStdlib.stdlibAvailable() - - @EnabledIf("stdlibAvailable") - @Test - fun `taint analysis on case1`() { - val path = "cases/case1.ir" - val project = loadProject(path) - val graph = PandaApplicationGraph(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(PandaMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - } - // Return the rules if they are not empty, otherwise return null: - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - // Enable untrusted loop bounds analysis: - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - - val method = project.classes.flatMap { it.methods }.single { it.name == "onRequest" } - logger.info { "Method: $method" } - val sinks = manager.analyze(listOf(method), timeout = 30.seconds) - logger.info { "Sinks: $sinks" } - assertTrue(sinks.isNotEmpty()) - } - - @EnabledIf("stdlibAvailable") - @Test - fun `taint analysis on case2`() { - val path = "cases/case2.ir" - val project = loadProject(path) - val graph = PandaApplicationGraph(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(PandaMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - if (method.isConstructor && method.enclosingClass.name == "escompat.ArrayBuffer") add( - TaintMethodSink( - method = method, - ruleNote = "ArrayBuffer constructor", - cwe = emptyList(), - condition = ContainsMark(position = Argument(1), mark = TaintMark("UNTRUSTED")), - ) - ) - } - // Return the rules if they are not empty, otherwise return null: - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - // Enable untrusted loop bounds analysis: - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - - val method = project.classes.single { - it.name == "Request" - }.methods.single { - it.name == "onRemoteMessageRequest" - } - logger.info { "Method: $method" } - val sinks = manager.analyze(listOf(method), timeout = 30.seconds) - logger.info { "Sinks: $sinks" } - assertTrue(sinks.isNotEmpty()) - } -} diff --git a/jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt b/jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt deleted file mode 100644 index fc358d299..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package panda - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.PandaStaticTraits -import org.jacodb.panda.staticvm.cfg.PandaApplicationGraph -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class PandaIfdsTest { - - companion object : PandaStaticTraits - - private fun stdlibAvailable() = EtsStdlib.stdlibAvailable() - - private fun loadProject(programName: String): PandaProject { - val program = loadProgram("/$programName.ir") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - return project - } - - @Test - @EnabledIf("stdlibAvailable") - fun `test taint analysis on program 2`() { - runTaintAnalysis("Program2") - } - - @Test - @EnabledIf("stdlibAvailable") - fun `test taint analysis on program with catch`() { - runTaintAnalysis("testCatch") - } - - private fun runTaintAnalysis(programName: String) { - val project = loadProject(programName) - val graph = PandaApplicationGraph(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(PandaMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "source") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "sink") add( - TaintMethodSink( - method = method, - ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - if (method.name == "pass") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - CopyAllMarks(from = Argument(0), to = Result) - ), - ) - ) - if (method.name == "validate") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - RemoveMark(mark = TaintMark("TAINT"), position = Argument(0)) - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val goodMethod = project.classes.flatMap { it.methods }.single { it.name == "good" } - logger.info { "good() method: $goodMethod" } - val goodSinks = manager.analyze(listOf(goodMethod), timeout = 60.seconds) - logger.info { "Sinks in good(): $goodSinks" } - Assertions.assertTrue(goodSinks.isEmpty()) - - val badMethod = project.classes.flatMap { it.methods }.single { it.name == "bad" } - logger.info { "bad() method: $badMethod" } - val badSinks = manager.analyze(listOf(badMethod), timeout = 60.seconds) - logger.info { "Sinks in bad(): $badSinks" } - Assertions.assertTrue(badSinks.isNotEmpty()) - } -} diff --git a/jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt b/jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt deleted file mode 100644 index 4bed0edea..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package panda - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.decodeFromStream -import org.jacodb.panda.staticvm.cfg.PandaApplicationGraph -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.ir.PandaProgramIr -import org.jacodb.panda.staticvm.ir.PandaProgramIr.Companion.json -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import java.io.FileInputStream -import kotlin.time.ExperimentalTime -import kotlin.time.measureTimedValue - -class PandaIrDeserializationTest { - - companion object { - private const val SAMPLE_FILE_PATH: String = "sample.abc.ir" - } - - private fun stdlibAvailable() = EtsStdlib.stdlibAvailable() - - @EnabledIf("stdlibAvailable") - @Test - fun deserializationTest() { - val filePath = SAMPLE_FILE_PATH - val program = loadProgram("/$filePath") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - val applicationGraph = PandaApplicationGraph(project) - } - - @EnabledIf("stdlibAvailable") - @Test - fun catchTest() { - val filePath = "testCatch.ir" - val program = loadProgram("/$filePath") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - val applicationGraph = PandaApplicationGraph(project) - } - - @EnabledIf("stdlibAvailable") - @OptIn(ExperimentalSerializationApi::class, ExperimentalTime::class) - @Test - fun pandaStdLibTest() { - val input = FileInputStream(EtsStdlib.STDLIB_FILE_PATH!!.path) - - val (program, deserializationDuration) = measureTimedValue { - json.decodeFromStream(input) - } - val (project, linkageDuration) = measureTimedValue { - PandaProject.fromProgramIr(program) - } - - println("deserialization: $deserializationDuration, linkage: $linkageDuration") - println("total: ${deserializationDuration + linkageDuration}") - } - - - @EnabledIf("stdlibAvailable") - @Test - fun pandaClasspathFlowGraphTest() { - val filePath = SAMPLE_FILE_PATH - val program = loadProgram("/$filePath") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - val method = project.findMethod("A.greet:i32;void;") - val flowGraph = method.flowGraph() - } -} diff --git a/jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt b/jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt deleted file mode 100644 index 17b5abf0a..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package panda - -import org.jacodb.panda.staticvm.cfg.toDot -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.ir.EtsStdlib -import org.jacodb.panda.staticvm.ir.PandaProgramIr -import org.jacodb.panda.staticvm.ir.dumpDot -import java.io.File -import java.nio.file.Files -import java.nio.file.Paths - -internal object EtsStdlib { - val STDLIB_FILE_PATH = EtsStdlib::class.java.getResource("stdlib.ir") - - fun stdlibAvailable(): Boolean { - val resource = STDLIB_FILE_PATH?.toURI() - return resource != null && Files.exists(Paths.get(resource)) - } -} - -fun loadProgram(path: String): PandaProgramIr { - val input = object {}::class.java.getResourceAsStream(path) - ?: error("Could not find resource: $path") - val program = PandaProgramIr.from(input) - return program -} - -object DumpIrToDot { - @JvmStatic - fun main(args: Array) { - val filePath = "try_catch_finally.abc.ir" - val program = loadProgram("/$filePath") - - val path = "dump" - val dotFile = File("$path.dot") - program.dumpDot(dotFile) - println("Generated DOT file: ${dotFile.absolutePath}") - for (format in listOf("pdf")) { - val formatFile = File("$path.$format") - val p = Runtime.getRuntime().exec("dot -T$format $dotFile -o $formatFile") - p.waitFor() - print(p.inputStream.bufferedReader().readText()) - print(p.errorStream.bufferedReader().readText()) - println("Generated ${format.uppercase()} file: ${formatFile.absolutePath}") - } - } -} - -object DumpCFGToDot { - @JvmStatic - fun main(args: Array) { - val filePath = "try_catch_finally.abc.ir" - val program = loadProgram("/$filePath") - val cfg = PandaProject.fromProgramIr(program, withStdLib = true) - .findMethod("ETSGLOBAL.main:void;") - .flowGraph() - - val path = "cfg_dump" - val dotFile = File("$path.dot") - dotFile.writer().use { it.write(cfg.toDot()) } - println("Generated DOT file: ${dotFile.absolutePath}") - for (format in listOf("pdf")) { - val formatFile = File("$path.$format") - val p = Runtime.getRuntime().exec("dot -T$format $dotFile -o $formatFile") - p.waitFor() - print(p.inputStream.bufferedReader().readText()) - print(p.errorStream.bufferedReader().readText()) - println("Generated ${format.uppercase()} file: ${formatFile.absolutePath}") - } - } -} diff --git a/jacodb-panda-static/src/test/resources/Program2.ets b/jacodb-panda-static/src/test/resources/Program2.ets deleted file mode 100644 index 6fd3722ab..000000000 --- a/jacodb-panda-static/src/test/resources/Program2.ets +++ /dev/null @@ -1,32 +0,0 @@ -type MaybeString = String | null - -function source(): MaybeString { - return null -} - -function getNull(): MaybeString { - return null -} - -function pass(data: MaybeString) { - return data -} - -function validate(data: MaybeString): MaybeString { - if (data == null) return "OK" - return data -} - -function sink(data: MaybeString) { - if (data == null) throw new Error("Error!") -} - -function bad() { - let data = source() - sink(pass(data)) -} - -function good() { - let data = source() - sink(validate(data)) -} diff --git a/jacodb-panda-static/src/test/resources/Program2.ir b/jacodb-panda-static/src/test/resources/Program2.ir deleted file mode 100644 index ae357b329..000000000 --- a/jacodb-panda-static/src/test/resources/Program2.ir +++ /dev/null @@ -1,1163 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v2", - "v3" - ], - "method": "ETSGLOBAL.pass:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v4", - "v5" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v7", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "bad", - "returnType": "void", - "signature": "ETSGLOBAL.bad:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v7" - ], - "opcode": "LoadString", - "string": "Error!", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10", - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9", - "v8" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v14", - "v11" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v6", - "v12" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v10", - "v13" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "sink", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "ETSGLOBAL.sink:std.core.String;void;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7", - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5" - ], - "opcode": "LoadClass", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "candidateType": "std.core.String", - "id": "v7", - "inputs": [ - "v0", - "v6", - "v5" - ], - "opcode": "CheckCast", - "type": "void" - }, - { - "id": "v8", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v10" - ], - "opcode": "LoadString", - "string": "OK", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v9" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "validate", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.validate:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v2" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "pass", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.pass:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v2", - "v3" - ], - "method": "ETSGLOBAL.validate:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v4", - "v5" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v7", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "good", - "returnType": "void", - "signature": "ETSGLOBAL.good:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "source", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.source:std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getNull", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.getNull:std.core.String;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case1.ets b/jacodb-panda-static/src/test/resources/cases/case1.ets deleted file mode 100644 index 9a6cea628..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case1.ets +++ /dev/null @@ -1,13 +0,0 @@ -interface Message { - readInt(): number; -} - -function onRequest(data: Message) { - let opt = data.readInt(); - - for (let i = 0; i < opt; i++) { - console.log(i); - } - - return true; -} diff --git a/jacodb-panda-static/src/test/resources/cases/case1.ir b/jacodb-panda-static/src/test/resources/cases/case1.ir deleted file mode 100644 index af9fe0c6c..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case1.ir +++ /dev/null @@ -1,966 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "readInt", - "returnType": "f64", - "signature": "Message.readInt:f64;" - } - ], - "name": "Message", - "simpleName": "Message", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "10p", - "v4" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v6", - "opcode": "Constant", - "type": "i32", - "users": [ - "9p" - ], - "value": 0 - }, - { - "id": "v16", - "opcode": "Constant", - "type": "i64", - "users": [ - "v15" - ], - "value": 0 - }, - { - "id": "v25", - "opcode": "Constant", - "type": "i32", - "users": [ - "v27", - "v24" - ], - "value": 1 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void" - }, - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "method": "Message.readInt:f64;", - "opcode": "CallVirtual", - "type": "f64", - "users": [ - "8p" - ] - }, - { - "id": "v7", - "opcode": "SaveStateDeoptimize", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "8p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v5", - "8p" - ], - "opcode": "Phi", - "type": "f64", - "users": [ - "8p", - "v14" - ] - }, - { - "id": "9p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v6", - "v24" - ], - "opcode": "Phi", - "type": "i32", - "users": [ - "v24", - "v23", - "v13" - ] - }, - { - "id": "10p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v0", - "10p" - ], - "opcode": "Phi", - "type": "ref", - "users": [ - "10p" - ] - }, - { - "id": "v12", - "opcode": "SafePoint", - "type": "void" - }, - { - "candidateType": "f64", - "id": "v13", - "inputs": [ - "9p" - ], - "opcode": "Cast", - "type": "f64", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "8p", - "v13" - ], - "opcode": "Cmp", - "operandsType": "f64", - "operator": "FCMPL", - "type": "i32", - "users": [ - "v15" - ] - }, - { - "id": "v15", - "inputs": [ - "v14", - "v16" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "immediate": 0, - "inputs": [ - "v15" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0, - 2 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v18", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v18" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v20", - "inputs": [ - "v19" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v22" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23", - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v20", - "v21" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22", - "9p", - "v21" - ], - "method": "std.core.Console.log:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v24", - "inputs": [ - "9p", - "v25" - ], - "opcode": "Add", - "type": "i32", - "users": [ - "9p" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v26", - "opcode": "SaveState", - "type": "void" - }, - { - "id": "v27", - "inputs": [ - "v25" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ] - } - ], - "name": "onRequest", - "parameters": [ - "Message" - ], - "returnType": "u1", - "signature": "ETSGLOBAL.onRequest:Message;u1;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case2.ets b/jacodb-panda-static/src/test/resources/cases/case2.ets deleted file mode 100644 index a2b5d1ddb..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case2.ets +++ /dev/null @@ -1,34 +0,0 @@ -interface Message { - readInt(): int; - - readBoolean(): boolean; -} - -class PixelMap { -} - -class Size { - height: int - width: int -} - -function createPixelMap(bytes: ArrayBuffer, size: Size): PixelMap { - return new PixelMap(); -} - -class Request { - onRemoteMessageRequest(data: Message): boolean { - try { - if (data.readBoolean()) { - let height = data.readInt(); - let width = data.readInt(); - let bytesNumber = data.readInt(); - let pixelMap = createPixelMap(new ArrayBuffer(bytesNumber), {height: height, width: width}); - } - return true; - } catch (e) { - console.log(e); - } - return false; - } -} diff --git a/jacodb-panda-static/src/test/resources/cases/case2.ir b/jacodb-panda-static/src/test/resources/cases/case2.ir deleted file mode 100644 index 5391cc6f6..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case2.ir +++ /dev/null @@ -1,1860 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "height", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "width", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "height", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "width", - "type": "i32" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Size.:void;" - } - ], - "name": "Size", - "simpleName": "Size", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "readInt", - "returnType": "i32", - "signature": "Message.readInt:i32;" - }, - { - "accessFlags": 1025, - "name": "readBoolean", - "returnType": "u1", - "signature": "Message.readBoolean:u1;" - } - ], - "name": "Message", - "simpleName": "Message", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "PixelMap.:void;" - } - ], - "name": "PixelMap", - "simpleName": "PixelMap", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3" - ], - "loadedClass": "PixelMap", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "objectClass": "PixelMap", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v8", - "v6" - ] - }, - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5", - "v7" - ], - "method": "PixelMap.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v8", - "inputs": [ - "v5" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "createPixelMap", - "parameters": [ - "escompat.ArrayBuffer", - "Size" - ], - "returnType": "PixelMap", - "signature": "ETSGLOBAL.createPixelMap:escompat.ArrayBuffer;Size;PixelMap;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Request.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 7, - "insts": [ - { - "id": "v12", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v13", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v28", - "v25", - "v22", - "v16" - ] - }, - { - "id": "v14", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v19", - "opcode": "Constant", - "type": "i64", - "users": [ - "v18" - ], - "value": 0 - }, - { - "id": "v58", - "opcode": "Constant", - "type": "i32", - "users": [ - "v64", - "v59" - ], - "value": 1 - }, - { - "id": "v67", - "opcode": "Constant", - "type": "i32", - "users": [ - "v77", - "v71" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 4 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 7 - ], - "successors": [ - 0, - 9 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v15", - "opcode": "SaveState", - "type": "void", - "users": [ - "v17", - "v16" - ] - }, - { - "id": "v16", - "inputs": [ - "v13", - "v15" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v17" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v17", - "inputs": [ - "v16", - "v15" - ], - "method": "Message.readBoolean:u1;", - "opcode": "CallVirtual", - "type": "u1", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "v17", - "v19" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "EQ", - "type": "u1", - "users": [ - "v20" - ] - }, - { - "id": "v20", - "immediate": 0, - "inputs": [ - "v18" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23", - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v13", - "v21" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v23" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v23", - "inputs": [ - "v22", - "v21" - ], - "method": "Message.readInt:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v42" - ] - }, - { - "id": "v24", - "opcode": "SaveState", - "type": "void", - "users": [ - "v26", - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v13", - "v24" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v26" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v26", - "inputs": [ - "v25", - "v24" - ], - "method": "Message.readInt:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v45" - ] - }, - { - "id": "v27", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29", - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v13", - "v27" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v29", - "inputs": [ - "v28", - "v27" - ], - "method": "Message.readInt:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v33" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v32", - "v31" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v31", - "inputs": [ - "v30" - ], - "loadedClass": "escompat.ArrayBuffer", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v32", - "inputs": [ - "v31", - "v30" - ], - "objectClass": "escompat.ArrayBuffer", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v47", - "v33" - ] - }, - { - "id": "v34", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v33", - "inputs": [ - "v32", - "v29", - "v34" - ], - "method": "escompat.ArrayBuffer.:i32;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v37", - "v36" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v36", - "inputs": [ - "v35" - ], - "loadedClass": "Size", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v37" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v37", - "inputs": [ - "v36", - "v35" - ], - "objectClass": "Size", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v47", - "v44", - "v41", - "v38" - ] - }, - { - "id": "v39", - "opcode": "SaveState", - "type": "void", - "users": [ - "v38" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v38", - "inputs": [ - "v37", - "v39" - ], - "method": "Size.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v40", - "opcode": "SaveState", - "type": "void", - "users": [ - "v41" - ] - }, - { - "id": "v41", - "inputs": [ - "v37", - "v40" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "catchers": [ - 9 - ], - "enclosingClass": "Size", - "field": "height", - "id": "v42", - "inputs": [ - "v41", - "v23" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "id": "v44", - "inputs": [ - "v37", - "v43" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v45" - ] - }, - { - "catchers": [ - 9 - ], - "enclosingClass": "Size", - "field": "width", - "id": "v45", - "inputs": [ - "v44", - "v26" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v48", - "v47" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v48", - "inputs": [ - "v46" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "catchers": [ - 9 - ], - "id": "v47", - "inputs": [ - "v32", - "v37", - "v46" - ], - "method": "ETSGLOBAL.createPixelMap:escompat.ArrayBuffer;Size;PixelMap;", - "opcode": "CallStatic", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v59", - "inputs": [ - "v58" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0, - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 1 - ], - "successors": [ - 8, - 9 - ] - }, - { - "id": 9, - "insts": [ - { - "id": "v11", - "opcode": "CatchPhi", - "type": "ref", - "users": [ - "v73" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 5 - ], - "successors": [ - 6 - ] - }, - { - "id": 6, - "insts": [ - { - "id": "v60", - "opcode": "SaveState", - "type": "void", - "users": [ - "v61" - ] - }, - { - "id": "v61", - "inputs": [ - "v60" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v62" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v62", - "inputs": [ - "v61" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v75" - ] - }, - { - "id": "v63", - "opcode": "SaveState", - "type": "void", - "users": [ - "v66", - "v65", - "v64" - ] - }, - { - "id": "v65", - "inputs": [ - "v63" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v66" - ] - }, - { - "id": "v64", - "inputs": [ - "v58", - "v63" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v66" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v66", - "inputs": [ - "v65", - "v64", - "v63" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v76", - "v69" - ] - }, - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v73", - "v71", - "v69" - ] - }, - { - "id": "v69", - "inputs": [ - "v66", - "v68" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v72", - "v73", - "v70" - ] - }, - { - "id": "v70", - "inputs": [ - "v69" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v71" - ] - }, - { - "id": "v71", - "inputs": [ - "v70", - "v67", - "v68" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v72" - ] - }, - { - "id": "v73", - "inputs": [ - "v69", - "v11", - "v68" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v72" - ] - }, - { - "id": "v72", - "inputs": [ - "v69", - "v71", - "v73" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v74", - "opcode": "SaveState", - "type": "void", - "users": [ - "v76", - "v75" - ] - }, - { - "id": "v75", - "inputs": [ - "v62", - "v74" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v76" - ] - }, - { - "id": "v76", - "inputs": [ - "v75", - "v66", - "v74" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 9 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v77", - "inputs": [ - "v67" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 8 - ] - }, - { - "id": 8, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5, - 3 - ] - } - ], - "name": "onRemoteMessageRequest", - "parameters": [ - "Message" - ], - "returnType": "u1", - "signature": "Request.onRemoteMessageRequest:Message;u1;" - } - ], - "name": "Request", - "simpleName": "Request", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case3.ets b/jacodb-panda-static/src/test/resources/cases/case3.ets deleted file mode 100644 index a95fc17f9..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case3.ets +++ /dev/null @@ -1,38 +0,0 @@ -class CommonEventPublishData { - code: int; - data: string; -} - -interface MyError { - code: int - name: string - message: string - stack?: string -} - -class CommonEventManager { - publish(event: string, options: CommonEventPublishData, callback: (err: MyError) => void) { - // publish event - } -} - -let commonEventManager = new CommonEventManager(); - -class CommonSecurity { - private publish: String = "" - - private publishEventWithData() { - let options: CommonEventPublishData = { - code: 1, - data: "Password123", - }; - // SINK: send with sensitive data - commonEventManager.publish("MyCommonEvent", options, (err) => { - if (err.code) { - this.publish = "publish event error: " + err.code + ", " + err.message + ", " + err.name + ", " + err.stack; - } else { - this.publish = "publish event with data success"; - } - }); - } -} diff --git a/jacodb-panda-static/src/test/resources/cases/case3.ir b/jacodb-panda-static/src/test/resources/cases/case3.ir deleted file mode 100644 index 1aa292665..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case3.ir +++ /dev/null @@ -1,3122 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "message", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "MyError.message:std.core.String;void;" - }, - { - "accessFlags": 1025, - "name": "stack", - "returnType": "std.core.Object", - "signature": "MyError.stack:std.core.Object;" - }, - { - "accessFlags": 1025, - "name": "name", - "returnType": "std.core.String", - "signature": "MyError.name:std.core.String;" - }, - { - "accessFlags": 1025, - "name": "code", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "MyError.code:i32;void;" - }, - { - "accessFlags": 1025, - "name": "message", - "returnType": "std.core.String", - "signature": "MyError.message:std.core.String;" - }, - { - "accessFlags": 1025, - "name": "stack", - "parameters": [ - "std.core.Object" - ], - "returnType": "void", - "signature": "MyError.stack:std.core.Object;void;" - }, - { - "accessFlags": 1025, - "name": "code", - "returnType": "i32", - "signature": "MyError.code:i32;" - }, - { - "accessFlags": 1025, - "name": "name", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "MyError.name:std.core.String;void;" - } - ], - "name": "MyError", - "simpleName": "MyError", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "data", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "code", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "code", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "data", - "type": "std.core.String" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "CommonEventPublishData", - "field": "data", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "CommonEventPublishData.:void;" - } - ], - "name": "CommonEventPublishData", - "simpleName": "CommonEventPublishData", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "field0", - "type": "CommonSecurity" - }, - { - "accessFlags": 1, - "name": "field0", - "type": "CommonSecurity" - } - ], - "interfaces": [ - "std.core.Function1" - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v5", - "inputs": [ - "v4" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8", - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v5", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v7", - "v1", - "v6" - ], - "method": "CommonSecurity.lambda$invoke$0:MyError;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "invoke", - "parameters": [ - "MyError" - ], - "returnType": "void", - "signature": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.invoke:MyError;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v5" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v3", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v6" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v0", - "v4" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v6", - "inputs": [ - "v5", - "v3" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v0", - "v7" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v9", - "inputs": [ - "v8", - "v1" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v10", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "parameters": [ - "CommonSecurity" - ], - "returnType": "void", - "signature": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.:CommonSecurity;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v19", - "v14", - "v11", - "v6" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v7", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v15", - "opcode": "LoadUndefined", - "type": "ref", - "users": [ - "v16" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v5", - "inputs": [ - "v4" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v13" - ] - }, - { - "id": "v6", - "inputs": [ - "v1", - "v7" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v6" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11", - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "opcode": "LoadClass", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "candidateType": "MyError", - "id": "v11", - "inputs": [ - "v1", - "v10", - "v9" - ], - "opcode": "CheckCast", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14", - "v13" - ] - }, - { - "id": "v13", - "inputs": [ - "v5", - "v12" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v13", - "v1", - "v12" - ], - "method": "CommonSecurity.lambda$invoke$0:MyError;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v16", - "inputs": [ - "v15" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v18", - "opcode": "SaveState", - "type": "void", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v18" - ], - "opcode": "LoadString", - "string": "MyError", - "type": "ref", - "users": [ - "v19" - ] - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v1", - "v17", - "v20" - ], - "intrinsicId": "StdCoreRuntimeFailedTypeCastException", - "opcode": "Intrinsic", - "type": "ref", - "users": [ - "v22" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v19", - "v21" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "invoke0", - "parameters": [ - "std.core.Object" - ], - "returnType": "std.core.Object", - "signature": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.invoke0:std.core.Object;std.core.Object;" - } - ], - "name": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "simpleName": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "superClass": "std.core.Object" - }, - { - "accessFlags": 8192, - "name": "ets/annotation/EnclosingClass", - "simpleName": "ets/annotation/EnclosingClass" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 2, - "name": "publish", - "type": "std.core.String" - }, - { - "accessFlags": 2, - "name": "publish", - "type": "std.core.String" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v6" - ], - "opcode": "LoadString", - "string": "", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v0", - "v7" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "enclosingClass": "CommonSecurity", - "field": "publish", - "id": "v9", - "inputs": [ - "v8", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v10", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "CommonSecurity.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v70", - "v65" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v53", - "v42", - "v31", - "v20", - "v4" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v7", - "opcode": "Constant", - "type": "i64", - "users": [ - "v6" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v1", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "method": "MyError.code:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5", - "v7" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "EQ", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v6" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11", - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v9" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v62", - "v59", - "v50", - "v45", - "v39", - "v34", - "v28", - "v23", - "v17", - "v12" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12" - ] - }, - { - "id": "v12", - "inputs": [ - "v11", - "v13" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v15", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v15" - ], - "opcode": "LoadString", - "string": "publish event error: ", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v11", - "v16" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "v17", - "v14", - "v16" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v19", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21", - "v20" - ] - }, - { - "id": "v20", - "inputs": [ - "v1", - "v19" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v20", - "v19" - ], - "method": "MyError.code:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v24" - ] - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24", - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v11", - "v22" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v23", - "v21", - "v22" - ], - "method": "std.core.StringBuilder.append:i32;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v26" - ], - "opcode": "LoadString", - "string": ", ", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "id": "v27", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29", - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v11", - "v27" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "id": "v29", - "inputs": [ - "v28", - "v25", - "v27" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v32", - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v1", - "v30" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "id": "v32", - "inputs": [ - "v31", - "v30" - ], - "method": "MyError.message:std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v35" - ] - }, - { - "id": "v33", - "opcode": "SaveState", - "type": "void", - "users": [ - "v35", - "v34" - ] - }, - { - "id": "v34", - "inputs": [ - "v11", - "v33" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v35" - ] - }, - { - "id": "v35", - "inputs": [ - "v34", - "v32", - "v33" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v37", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v37" - ], - "opcode": "LoadString", - "string": ", ", - "type": "ref", - "users": [ - "v40" - ] - }, - { - "id": "v38", - "opcode": "SaveState", - "type": "void", - "users": [ - "v40", - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v11", - "v38" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v39", - "v36", - "v38" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v1", - "v41" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "id": "v43", - "inputs": [ - "v42", - "v41" - ], - "method": "MyError.name:std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v44", - "opcode": "SaveState", - "type": "void", - "users": [ - "v46", - "v45" - ] - }, - { - "id": "v45", - "inputs": [ - "v11", - "v44" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v46", - "inputs": [ - "v45", - "v43", - "v44" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v48", - "opcode": "SaveState", - "type": "void", - "users": [ - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v48" - ], - "opcode": "LoadString", - "string": ", ", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "id": "v49", - "opcode": "SaveState", - "type": "void", - "users": [ - "v51", - "v50" - ] - }, - { - "id": "v50", - "inputs": [ - "v11", - "v49" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "id": "v51", - "inputs": [ - "v50", - "v47", - "v49" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v52", - "opcode": "SaveState", - "type": "void", - "users": [ - "v54", - "v53" - ] - }, - { - "id": "v53", - "inputs": [ - "v1", - "v52" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v54" - ] - }, - { - "id": "v54", - "inputs": [ - "v53", - "v52" - ], - "method": "MyError.stack:std.core.Object;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v56" - ] - }, - { - "id": "v55", - "opcode": "SaveState", - "type": "void", - "users": [ - "v57", - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v54", - "v55" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v57" - ] - }, - { - "id": "v57", - "inputs": [ - "v56", - "v55" - ], - "method": "std.core.Object.toString:std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "id": "v58", - "opcode": "SaveState", - "type": "void", - "users": [ - "v60", - "v59" - ] - }, - { - "id": "v59", - "inputs": [ - "v11", - "v58" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "id": "v60", - "inputs": [ - "v59", - "v57", - "v58" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v61", - "opcode": "SaveState", - "type": "void", - "users": [ - "v63", - "v62" - ] - }, - { - "id": "v62", - "inputs": [ - "v11", - "v61" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v63" - ] - }, - { - "id": "v63", - "inputs": [ - "v62", - "v61" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v66" - ] - }, - { - "id": "v64", - "opcode": "SaveState", - "type": "void", - "users": [ - "v65" - ] - }, - { - "id": "v65", - "inputs": [ - "v0", - "v64" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v66" - ] - }, - { - "enclosingClass": "CommonSecurity", - "field": "publish", - "id": "v66", - "inputs": [ - "v65", - "v63" - ], - "opcode": "StoreObject", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v67" - ] - }, - { - "id": "v67", - "inputs": [ - "v68" - ], - "opcode": "LoadString", - "string": "publish event with data success", - "type": "ref", - "users": [ - "v71" - ] - }, - { - "id": "v69", - "opcode": "SaveState", - "type": "void", - "users": [ - "v70" - ] - }, - { - "id": "v70", - "inputs": [ - "v0", - "v69" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v71" - ] - }, - { - "enclosingClass": "CommonSecurity", - "field": "publish", - "id": "v71", - "inputs": [ - "v70", - "v67" - ], - "opcode": "StoreObject", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v75", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 1 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ] - } - ], - "name": "lambda$invoke$0", - "parameters": [ - "MyError" - ], - "returnType": "void", - "signature": "CommonSecurity.lambda$invoke$0:MyError;void;" - }, - { - "accessFlags": 2, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v7", - "opcode": "Constant", - "type": "i32", - "users": [ - "v10" - ], - "value": 1 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "CommonEventPublishData", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "objectClass": "CommonEventPublishData", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v28", - "v14", - "v9", - "v5" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v6" - ], - "method": "CommonEventPublishData.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v4", - "v8" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "enclosingClass": "CommonEventPublishData", - "field": "code", - "id": "v10", - "inputs": [ - "v9", - "v7" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v12" - ], - "opcode": "LoadString", - "string": "Password123", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v4", - "v13" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "enclosingClass": "CommonEventPublishData", - "field": "data", - "id": "v15", - "inputs": [ - "v14", - "v11" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v16" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "commonEventManager", - "id": "v18", - "inputs": [ - "v17" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v27" - ] - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v20" - ], - "opcode": "LoadString", - "string": "MyCommonEvent", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23", - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v21" - ], - "loadedClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22", - "v21" - ], - "objectClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v28", - "v24" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v23", - "v0", - "v25" - ], - "method": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.:CommonSecurity;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v28", - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v18", - "v26" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v27", - "v19", - "v4", - "v23", - "v26" - ], - "method": "CommonEventManager.publish:std.core.String;CommonEventPublishData;std.core.Function1;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v29", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "publishEventWithData", - "returnType": "void", - "signature": "CommonSecurity.publishEventWithData:void;" - } - ], - "name": "CommonSecurity", - "simpleName": "CommonSecurity", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 9, - "name": "commonEventManager", - "type": "CommonEventManager" - }, - { - "accessFlags": 9, - "name": "commonEventManager", - "type": "CommonEventManager" - } - ], - "methods": [ - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL._$init$_:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v3", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3", - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "loadedClass": "CommonEventManager", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2", - "v1" - ], - "objectClass": "CommonEventManager", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v8", - "v4" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v5" - ], - "method": "CommonEventManager.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v6" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "commonEventManager", - "id": "v8", - "inputs": [ - "v7", - "v3" - ], - "opcode": "StoreStatic", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "CommonEventManager.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "index": 2, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v3", - "index": 3, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v4", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "publish", - "parameters": [ - "std.core.String", - "CommonEventPublishData", - "std.core.Function1" - ], - "returnType": "void", - "signature": "CommonEventManager.publish:std.core.String;CommonEventPublishData;std.core.Function1;void;" - } - ], - "name": "CommonEventManager", - "simpleName": "CommonEventManager", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 8192, - "name": "ets/annotation/InnerClass", - "simpleName": "ets/annotation/InnerClass" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case4.ets b/jacodb-panda-static/src/test/resources/cases/case4.ets deleted file mode 100644 index 61ed48503..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case4.ets +++ /dev/null @@ -1,99 +0,0 @@ -interface Context { -} - -declare function getContext(): Context; - -class AtManager { -} - -class AbilityAccessCtrl { - createAtManager(): AtManager { - return {}; - } -} - -let abilityAccessCtrl = new AbilityAccessCtrl(); - -type Permissions = string; - -class PermissionUtil { - static requestPermissionsFromUser(permissions: Permissions[]): boolean { - return true; - } -} - -class Settings { - setValue(context: Context, key: string, value: string) { - } - - getValue(context: Context, key: string): string { - return ""; - } -} - -let settings = new Settings(); - -class Pasteboard { - clear() { - // - } - - setPasteData(pasteData: string) { - // - } -} - -// From 'pasteboard' module. -function getSystemPasteboard(): Pasteboard { - return new Pasteboard(); -} - -// From 'pasteboard' module. -function createPlainTextData(data: string): string { - return data; -} - -class Setting { - private context: Context = getContext(); - - setData() { - let atManager = abilityAccessCtrl.createAtManager(); - let message = "helloWorld"; - let password = "Password123"; - try { - // Verify whether the application is granted setting permission - const permissions: Permissions[] = ['ohos.permission.MANAGE_SECURE_SETTINGS']; - if (PermissionUtil.requestPermissionsFromUser(permissions)) { - settings.setValue(this.context, 'message', message); - - // SINK: The application stores the password of sensitive information in the settings database - settings.setValue(this.context, "password", password) - } else { - // Unauthorized - } - } catch (err) { - return; - } - } - - // SINK: Any application can directly read the data of the settings database, causing information leakage - getData() { - let value = settings.getValue(this.context, "password") - console.log("get settings customs data password: " + value) - } - - // It is forbidden to store severity level data in the clipboard - pasteboard() { - // Counterexample: Text copy - console.log('Get SystemPasteboard') - let systemPasteboard = getSystemPasteboard() - systemPasteboard.clear() - - let password = 'Password123' - console.log('createPlainTextData = ' + password) - let pasteData = createPlainTextData(password) - - console.log('Writes PasteData to the pasteboard') - systemPasteboard.setPasteData(pasteData) - } -} diff --git a/jacodb-panda-static/src/test/resources/cases/case4.ir b/jacodb-panda-static/src/test/resources/cases/case4.ir deleted file mode 100644 index 4814377ad..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case4.ir +++ /dev/null @@ -1,4544 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Pasteboard.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "setPasteData", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "Pasteboard.setPasteData:std.core.String;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "clear", - "returnType": "void", - "signature": "Pasteboard.clear:void;" - } - ], - "name": "Pasteboard", - "simpleName": "Pasteboard", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "AtManager.:void;" - } - ], - "name": "AtManager", - "simpleName": "AtManager", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "Context", - "simpleName": "Context", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 2, - "name": "context", - "type": "Context" - }, - { - "accessFlags": 2, - "name": "context", - "type": "Context" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v16", - "opcode": "Constant", - "type": "i32", - "users": [ - "v18" - ], - "value": 1 - }, - { - "id": "v21", - "opcode": "Constant", - "type": "i32", - "users": [ - "v41" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v4", - "inputs": [ - "v3" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v0", - "v5" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "enclosingClass": "Setting", - "field": "context", - "id": "v7", - "inputs": [ - "v6" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v12" - ] - }, - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v9" - ], - "opcode": "LoadString", - "string": "password", - "type": "ref", - "users": [ - "v12" - ] - }, - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12", - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v4", - "v10" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v12" - ] - }, - { - "id": "v12", - "inputs": [ - "v11", - "v7", - "v8", - "v10" - ], - "method": "Settings.getValue:Context;std.core.String;std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v34" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v13" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v15", - "inputs": [ - "v14" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v45" - ] - }, - { - "id": "v17", - "opcode": "SaveState", - "type": "void", - "users": [ - "v20", - "v19", - "v18" - ] - }, - { - "id": "v19", - "inputs": [ - "v17" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v18", - "inputs": [ - "v16", - "v17" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v20" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v20", - "inputs": [ - "v19", - "v18", - "v17" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v46", - "v39" - ] - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24", - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v23", - "v22" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v36", - "v33", - "v30", - "v25" - ] - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v24", - "v26" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v28", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v28" - ], - "opcode": "LoadString", - "string": "get settings customs data password: ", - "type": "ref", - "users": [ - "v31" - ] - }, - { - "id": "v29", - "opcode": "SaveState", - "type": "void", - "users": [ - "v31", - "v30" - ] - }, - { - "id": "v30", - "inputs": [ - "v24", - "v29" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v30", - "v27", - "v29" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v32", - "opcode": "SaveState", - "type": "void", - "users": [ - "v34", - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v24", - "v32" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v34" - ] - }, - { - "id": "v34", - "inputs": [ - "v33", - "v12", - "v32" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v37", - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v24", - "v35" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v37" - ] - }, - { - "id": "v37", - "inputs": [ - "v36", - "v35" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "id": "v38", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v41", - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v20", - "v38" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v42", - "v43", - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v39" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v41" - ] - }, - { - "id": "v41", - "inputs": [ - "v40", - "v21", - "v38" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v42" - ] - }, - { - "id": "v43", - "inputs": [ - "v39", - "v37", - "v38" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v39", - "v41", - "v43" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v44", - "opcode": "SaveState", - "type": "void", - "users": [ - "v46", - "v45" - ] - }, - { - "id": "v45", - "inputs": [ - "v15", - "v44" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v46", - "inputs": [ - "v45", - "v20", - "v44" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v47", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getData", - "returnType": "void", - "signature": "Setting.getData:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 8, - "insts": [ - { - "id": "v11", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v58", - "v47" - ] - }, - { - "id": "v12", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v23", - "opcode": "Constant", - "type": "i32", - "users": [ - "v25" - ], - "value": 1 - }, - { - "id": "v28", - "opcode": "Constant", - "type": "i32", - "users": [ - "v34" - ], - "value": 0 - }, - { - "id": "v41", - "opcode": "Constant", - "type": "i64", - "users": [ - "v40" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v13" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "abilityAccessCtrl", - "id": "v15", - "inputs": [ - "v14" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v17" - ] - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v15", - "v16" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "v17", - "v16" - ], - "method": "AbilityAccessCtrl.createAtManager:AtManager;", - "opcode": "CallVirtual", - "type": "ref" - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v20" - ], - "opcode": "LoadString", - "string": "helloWorld", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v22" - ], - "opcode": "LoadString", - "string": "Password123", - "type": "ref", - "users": [ - "v64" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 4 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 6, - 10 - ] - }, - { - "id": 6, - "insts": [ - { - "id": "v24", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27", - "v26", - "v25" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v26", - "inputs": [ - "v24" - ], - "loadedClass": "[Lstd/core/String;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v27" - ] - }, - { - "id": "v25", - "inputs": [ - "v23", - "v24" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v27" - ] - }, - { - "arrayType": "std.core.String[]", - "catchers": [ - 10 - ], - "id": "v27", - "inputs": [ - "v26", - "v25", - "v24" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "66p", - "65p", - "v38", - "v32" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v29", - "inputs": [ - "v30" - ], - "opcode": "LoadString", - "string": "ohos.permission.MANAGE_SECURE_SETTINGS", - "type": "ref", - "users": [ - "v36" - ] - }, - { - "id": "v31", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36", - "v34", - "v32" - ] - }, - { - "id": "v32", - "inputs": [ - "v27", - "v31" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v35", - "v36", - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v32" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v34" - ] - }, - { - "id": "v34", - "inputs": [ - "v33", - "v28", - "v31" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v35" - ] - }, - { - "id": "v36", - "inputs": [ - "v32", - "v29", - "v31" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v35" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v35", - "inputs": [ - "v32", - "v34", - "v36" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v37", - "opcode": "SaveState", - "type": "void", - "users": [ - "v39", - "v38" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v39", - "inputs": [ - "v37" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "catchers": [ - 10 - ], - "id": "v38", - "inputs": [ - "v27", - "v37" - ], - "method": "PermissionUtil.requestPermissionsFromUser:std.core.String[];u1;", - "opcode": "CallStatic", - "type": "u1", - "users": [ - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v38", - "v41" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "EQ", - "type": "u1", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "immediate": 0, - "inputs": [ - "v40" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v44", - "inputs": [ - "v43" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v45" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v45", - "inputs": [ - "v44" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v52" - ] - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v11", - "v46" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v48" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "Setting", - "field": "context", - "id": "v48", - "inputs": [ - "v47" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "id": "v50", - "opcode": "SaveState", - "type": "void", - "users": [ - "v49" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v49", - "inputs": [ - "v50" - ], - "opcode": "LoadString", - "string": "message", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "id": "v51", - "opcode": "SaveState", - "type": "void", - "users": [ - "v53", - "v52" - ] - }, - { - "id": "v52", - "inputs": [ - "v45", - "v51" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v53", - "inputs": [ - "v52", - "v48", - "v49", - "v19", - "v51" - ], - "method": "Settings.setValue:Context;std.core.String;std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v54", - "opcode": "SaveState", - "type": "void", - "users": [ - "v55" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v55", - "inputs": [ - "v54" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v56" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v56", - "inputs": [ - "v55" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "65p", - "v63" - ] - }, - { - "id": "v57", - "opcode": "SaveState", - "type": "void", - "users": [ - "v58" - ] - }, - { - "id": "v58", - "inputs": [ - "v11", - "v57" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v59" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "Setting", - "field": "context", - "id": "v59", - "inputs": [ - "v58" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "66p", - "v64" - ] - }, - { - "id": "v61", - "opcode": "SaveState", - "type": "void", - "users": [ - "v60" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v60", - "inputs": [ - "v61" - ], - "opcode": "LoadString", - "string": "password", - "type": "ref", - "users": [ - "v64" - ] - }, - { - "id": "v62", - "opcode": "SaveState", - "type": "void", - "users": [ - "v64", - "v63" - ] - }, - { - "id": "v63", - "inputs": [ - "v56", - "v62" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v64" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v64", - "inputs": [ - "v63", - "v59", - "v60", - "v21", - "v62" - ], - "method": "Settings.setValue:Context;std.core.String;std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "65p", - "inputBlocks": [ - 6, - 2 - ], - "inputs": [ - "v27", - "v56" - ], - "opcode": "Phi", - "type": "ref" - }, - { - "id": "66p", - "inputBlocks": [ - 6, - 2 - ], - "inputs": [ - "v27", - "v59" - ], - "opcode": "Phi", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6, - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 1 - ], - "successors": [ - 3, - 10 - ] - }, - { - "id": 10, - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 5 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "insts": [ - { - "id": "v70", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 10 - ], - "successors": [ - 9 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v71", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 9 - ] - }, - { - "id": 9, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 7, - 3 - ] - } - ], - "name": "setData", - "returnType": "void", - "signature": "Setting.setData:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v9", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7", - "v6" - ] - }, - { - "id": "v7", - "inputs": [ - "v5" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v6", - "inputs": [ - "v5" - ], - "method": "ETSGLOBAL.getContext:Context;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v0", - "v8" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "enclosingClass": "Setting", - "field": "context", - "id": "v10", - "inputs": [ - "v9", - "v6" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v11", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Setting.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "Constant", - "type": "i32", - "users": [ - "v69", - "v34", - "v7" - ], - "value": 1 - }, - { - "id": "v10", - "opcode": "Constant", - "type": "i32", - "users": [ - "v77", - "v56", - "v16" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v4", - "inputs": [ - "v3" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9", - "v8", - "v7" - ] - }, - { - "id": "v8", - "inputs": [ - "v6" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "id": "v7", - "inputs": [ - "v5", - "v6" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v9" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v9", - "inputs": [ - "v8", - "v7", - "v6" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v21", - "v14" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v12" - ], - "opcode": "LoadString", - "string": "Get SystemPasteboard", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v16", - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v9", - "v13" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v17", - "v18", - "v15" - ] - }, - { - "id": "v15", - "inputs": [ - "v14" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v16" - ] - }, - { - "id": "v16", - "inputs": [ - "v15", - "v10", - "v13" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v17" - ] - }, - { - "id": "v18", - "inputs": [ - "v14", - "v11", - "v13" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v14", - "v16", - "v18" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v19", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21", - "v20" - ] - }, - { - "id": "v20", - "inputs": [ - "v4", - "v19" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v20", - "v9", - "v19" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24", - "v23" - ] - }, - { - "id": "v24", - "inputs": [ - "v22" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v23", - "inputs": [ - "v22" - ], - "method": "ETSGLOBAL.getSystemPasteboard:Pasteboard;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v84", - "v26" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27", - "v26" - ] - }, - { - "id": "v26", - "inputs": [ - "v23", - "v25" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v26", - "v25" - ], - "method": "Pasteboard.clear:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v29", - "opcode": "SaveState", - "type": "void", - "users": [ - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v29" - ], - "opcode": "LoadString", - "string": "Password123", - "type": "ref", - "users": [ - "v63", - "v49" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v30" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v32", - "inputs": [ - "v31" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "id": "v33", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36", - "v35", - "v34" - ] - }, - { - "id": "v35", - "inputs": [ - "v33" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v36" - ] - }, - { - "id": "v34", - "inputs": [ - "v5", - "v33" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v36" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v36", - "inputs": [ - "v35", - "v34", - "v33" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v61", - "v54" - ] - }, - { - "id": "v37", - "opcode": "SaveState", - "type": "void", - "users": [ - "v39", - "v38" - ] - }, - { - "id": "v38", - "inputs": [ - "v37" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v38", - "v37" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v51", - "v48", - "v45", - "v40" - ] - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v39", - "v41" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v43" - ], - "opcode": "LoadString", - "string": "createPlainTextData = ", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v44", - "opcode": "SaveState", - "type": "void", - "users": [ - "v46", - "v45" - ] - }, - { - "id": "v45", - "inputs": [ - "v39", - "v44" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v46", - "inputs": [ - "v45", - "v42", - "v44" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v47", - "opcode": "SaveState", - "type": "void", - "users": [ - "v49", - "v48" - ] - }, - { - "id": "v48", - "inputs": [ - "v39", - "v47" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v49" - ] - }, - { - "id": "v49", - "inputs": [ - "v48", - "v28", - "v47" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v50", - "opcode": "SaveState", - "type": "void", - "users": [ - "v52", - "v51" - ] - }, - { - "id": "v51", - "inputs": [ - "v39", - "v50" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v52" - ] - }, - { - "id": "v52", - "inputs": [ - "v51", - "v50" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v58" - ] - }, - { - "id": "v53", - "opcode": "SaveState", - "type": "void", - "users": [ - "v58", - "v56", - "v54" - ] - }, - { - "id": "v54", - "inputs": [ - "v36", - "v53" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v57", - "v58", - "v55" - ] - }, - { - "id": "v55", - "inputs": [ - "v54" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v55", - "v10", - "v53" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v57" - ] - }, - { - "id": "v58", - "inputs": [ - "v54", - "v52", - "v53" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v57" - ] - }, - { - "id": "v57", - "inputs": [ - "v54", - "v56", - "v58" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v59", - "opcode": "SaveState", - "type": "void", - "users": [ - "v61", - "v60" - ] - }, - { - "id": "v60", - "inputs": [ - "v32", - "v59" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v61" - ] - }, - { - "id": "v61", - "inputs": [ - "v60", - "v36", - "v59" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v62", - "opcode": "SaveState", - "type": "void", - "users": [ - "v64", - "v63" - ] - }, - { - "id": "v64", - "inputs": [ - "v62" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v63", - "inputs": [ - "v28", - "v62" - ], - "method": "ETSGLOBAL.createPlainTextData:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v85" - ] - }, - { - "id": "v65", - "opcode": "SaveState", - "type": "void", - "users": [ - "v66" - ] - }, - { - "id": "v66", - "inputs": [ - "v65" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v67" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v67", - "inputs": [ - "v66" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v81" - ] - }, - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v71", - "v70", - "v69" - ] - }, - { - "id": "v70", - "inputs": [ - "v68" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v71" - ] - }, - { - "id": "v69", - "inputs": [ - "v5", - "v68" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v71" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v71", - "inputs": [ - "v70", - "v69", - "v68" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v82", - "v75" - ] - }, - { - "id": "v73", - "opcode": "SaveState", - "type": "void", - "users": [ - "v72" - ] - }, - { - "id": "v72", - "inputs": [ - "v73" - ], - "opcode": "LoadString", - "string": "Writes PasteData to the pasteboard", - "type": "ref", - "users": [ - "v79" - ] - }, - { - "id": "v74", - "opcode": "SaveState", - "type": "void", - "users": [ - "v79", - "v77", - "v75" - ] - }, - { - "id": "v75", - "inputs": [ - "v71", - "v74" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v78", - "v79", - "v76" - ] - }, - { - "id": "v76", - "inputs": [ - "v75" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v77" - ] - }, - { - "id": "v77", - "inputs": [ - "v76", - "v10", - "v74" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v78" - ] - }, - { - "id": "v79", - "inputs": [ - "v75", - "v72", - "v74" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v78" - ] - }, - { - "id": "v78", - "inputs": [ - "v75", - "v77", - "v79" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v80", - "opcode": "SaveState", - "type": "void", - "users": [ - "v82", - "v81" - ] - }, - { - "id": "v81", - "inputs": [ - "v67", - "v80" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v82" - ] - }, - { - "id": "v82", - "inputs": [ - "v81", - "v71", - "v80" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v83", - "opcode": "SaveState", - "type": "void", - "users": [ - "v85", - "v84" - ] - }, - { - "id": "v84", - "inputs": [ - "v23", - "v83" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v85" - ] - }, - { - "id": "v85", - "inputs": [ - "v84", - "v63", - "v83" - ], - "method": "Pasteboard.setPasteData:std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v86", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "pasteboard", - "returnType": "void", - "signature": "Setting.pasteboard:void;" - } - ], - "name": "Setting", - "simpleName": "Setting", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 9, - "name": "settings", - "type": "Settings" - }, - { - "accessFlags": 9, - "name": "abilityAccessCtrl", - "type": "AbilityAccessCtrl" - }, - { - "accessFlags": 9, - "name": "abilityAccessCtrl", - "type": "AbilityAccessCtrl" - }, - { - "accessFlags": 9, - "name": "settings", - "type": "Settings" - } - ], - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ] - } - ], - "name": "getContext", - "returnType": "Context", - "signature": "ETSGLOBAL.getContext:Context;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3", - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "loadedClass": "AbilityAccessCtrl", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2", - "v1" - ], - "objectClass": "AbilityAccessCtrl", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v8", - "v4" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v5" - ], - "method": "AbilityAccessCtrl.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v6" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "abilityAccessCtrl", - "id": "v8", - "inputs": [ - "v7", - "v3" - ], - "opcode": "StoreStatic", - "type": "ref" - }, - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11", - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "loadedClass": "Settings", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v9" - ], - "objectClass": "Settings", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v16", - "v12" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12" - ] - }, - { - "id": "v12", - "inputs": [ - "v11", - "v13" - ], - "method": "Settings.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v14", - "opcode": "SaveState", - "type": "void", - "users": [ - "v15" - ] - }, - { - "id": "v15", - "inputs": [ - "v14" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v16" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v16", - "inputs": [ - "v15", - "v11" - ], - "opcode": "StoreStatic", - "type": "ref" - }, - { - "id": "v17", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL._$init$_:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v3", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v2" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "createPlainTextData", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.createPlainTextData:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3", - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "loadedClass": "Pasteboard", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2", - "v1" - ], - "objectClass": "Pasteboard", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v6", - "v4" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v5" - ], - "method": "Pasteboard.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "inputs": [ - "v3" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getSystemPasteboard", - "returnType": "Pasteboard", - "signature": "ETSGLOBAL.getSystemPasteboard:Pasteboard;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "AbilityAccessCtrl.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "AtManager", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "objectClass": "AtManager", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v7", - "v5" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v6" - ], - "method": "AtManager.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v7", - "inputs": [ - "v4" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "createAtManager", - "returnType": "AtManager", - "signature": "AbilityAccessCtrl.createAtManager:AtManager;" - } - ], - "name": "AbilityAccessCtrl", - "simpleName": "AbilityAccessCtrl", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "index": 2, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v3", - "index": 3, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v4", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "setValue", - "parameters": [ - "Context", - "std.core.String", - "std.core.String" - ], - "returnType": "void", - "signature": "Settings.setValue:Context;std.core.String;std.core.String;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "index": 2, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v3", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v5" - ], - "opcode": "LoadString", - "string": "", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v4" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getValue", - "parameters": [ - "Context", - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "Settings.getValue:Context;std.core.String;std.core.String;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Settings.:void;" - } - ], - "name": "Settings", - "simpleName": "Settings", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "PermissionUtil.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "Constant", - "type": "i32", - "users": [ - "v3" - ], - "value": 1 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v2" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "requestPermissionsFromUser", - "parameters": [ - "std.core.String[]" - ], - "returnType": "u1", - "signature": "PermissionUtil.requestPermissionsFromUser:std.core.String[];u1;" - } - ], - "name": "PermissionUtil", - "simpleName": "PermissionUtil", - "superClass": "std.core.Object" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/sample.abc.ir b/jacodb-panda-static/src/test/resources/sample.abc.ir deleted file mode 100644 index 5530b9a04..000000000 --- a/jacodb-panda-static/src/test/resources/sample.abc.ir +++ /dev/null @@ -1,4788 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "kek", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "kek", - "type": "i32" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ABVGDEJOZH.:void;" - } - ], - "name": "ABVGDEJOZH", - "simpleName": "ABVGDEJOZH", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 1025, - "name": "greet", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "A0.greet:i32;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "A0.:void;" - } - ], - "name": "A0", - "simpleName": "A0", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "t", - "type": "std.core.Object" - }, - { - "accessFlags": 1, - "name": "t", - "type": "std.core.Object" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "P", - "field": "t", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "P.:void;" - } - ], - "name": "P", - "simpleName": "P", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 0, - "name": "a", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "b", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "c", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "c", - "type": "std.core.String" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "A.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "A1", - "field": "c", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "A1.:void;" - } - ], - "name": "A1", - "simpleName": "A1", - "superClass": "A" - }, - { - "accessFlags": 1537, - "name": "I2", - "simpleName": "I2", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v3" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v1" - ], - "opcode": "Add", - "type": "i32", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "aplusb", - "parameters": [ - "i32", - "i32" - ], - "returnType": "i32", - "signature": "ETSGLOBAL.aplusb:i32;i32;i32;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v7", - "v6", - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v7" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v3", - "opcode": "Constant", - "type": "i32", - "users": [ - "v4" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "inputs": [ - "v3", - "v0" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "NE", - "type": "u1", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "immediate": 0, - "inputs": [ - "v4" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v6", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "inputs": [ - "v0", - "v1" - ], - "opcode": "Mul", - "type": "i32", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v7" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 1 - ] - } - ], - "name": "aorb", - "parameters": [ - "i32", - "i32" - ], - "returnType": "i32", - "signature": "ETSGLOBAL.aorb:i32;i32;i32;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 6, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "Constant", - "type": "i32", - "users": [ - "10p" - ], - "value": 353 - }, - { - "id": "v2", - "opcode": "Constant", - "type": "i32", - "users": [ - "v26", - "v5" - ], - "value": 2 - }, - { - "id": "v3", - "opcode": "Constant", - "type": "i32", - "users": [ - "v26", - "v5" - ], - "value": 3 - }, - { - "id": "v6", - "opcode": "Constant", - "type": "i32", - "users": [ - "18p", - "v44", - "v7" - ], - "value": 0 - }, - { - "id": "v9", - "opcode": "Constant", - "type": "i32", - "users": [ - "10p" - ], - "value": 11 - }, - { - "id": "v15", - "opcode": "Constant", - "type": "i32", - "users": [ - "18p", - "v44", - "v16" - ], - "value": 1 - }, - { - "id": "v35", - "opcode": "Constant", - "type": "i32", - "users": [ - "v38" - ], - "value": 42 - }, - { - "id": "v39", - "opcode": "Constant", - "type": "i32", - "users": [ - "v42" - ], - "value": 5 - }, - { - "id": "v45", - "opcode": "Constant", - "type": "i32", - "users": [ - "v49" - ], - "value": 4 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v2", - "v3", - "v4" - ], - "method": "ETSGLOBAL.aplusb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v6", - "v5" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v7" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "10p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v1", - "v9" - ], - "opcode": "Phi", - "type": "i32", - "users": [ - "v16" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v13" - ] - }, - { - "id": "v13", - "inputs": [ - "v12" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v14" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v14", - "inputs": [ - "v13" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v16", - "inputs": [ - "v15", - "10p" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "NE", - "type": "u1", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "immediate": 0, - "inputs": [ - "v16" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0, - 2 - ], - "successors": [ - 3, - 4 - ] - }, - { - "id": 4, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 5 - ] - }, - { - "id": 3, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "18p", - "inputBlocks": [ - 4, - 3 - ], - "inputs": [ - "v15", - "v6" - ], - "opcode": "Phi", - "type": "u1", - "users": [ - "v21" - ] - }, - { - "id": "v19", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21", - "v20" - ] - }, - { - "id": "v20", - "inputs": [ - "v14", - "v19" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v20", - "18p", - "v19" - ], - "method": "std.core.Console.print:u1;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v24", - "inputs": [ - "v23" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v26" - ] - }, - { - "id": "v26", - "inputs": [ - "v2", - "v3", - "v25" - ], - "method": "ETSGLOBAL.aplusb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32", - "users": [ - "v29" - ] - }, - { - "id": "v27", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29", - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v24", - "v27" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "id": "v29", - "inputs": [ - "v28", - "v26", - "v27" - ], - "method": "std.core.Console.print:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v32", - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v30" - ], - "loadedClass": "A", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "id": "v32", - "inputs": [ - "v31", - "v30" - ], - "objectClass": "A", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v56", - "v41", - "v37", - "v33" - ] - }, - { - "id": "v34", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v32", - "v34" - ], - "method": "A.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v36", - "opcode": "SaveState", - "type": "void", - "users": [ - "v38", - "v37" - ] - }, - { - "id": "v37", - "inputs": [ - "v32", - "v36" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v38" - ] - }, - { - "id": "v38", - "inputs": [ - "v37", - "v35", - "v36" - ], - "method": "A.greet:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v40", - "opcode": "SaveState", - "type": "void", - "users": [ - "v42", - "v41" - ] - }, - { - "id": "v41", - "inputs": [ - "v32", - "v40" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v41", - "v39", - "v40" - ], - "method": "A.foo:i32;i32;", - "opcode": "CallVirtual", - "type": "i32" - }, - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "id": "v44", - "inputs": [ - "v15", - "v6", - "v43" - ], - "method": "ETSGLOBAL.aorb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32" - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v48", - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v46" - ], - "loadedClass": "B", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v48" - ] - }, - { - "id": "v48", - "inputs": [ - "v47", - "v46" - ], - "objectClass": "B", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v55", - "v49" - ] - }, - { - "id": "v50", - "opcode": "SaveState", - "type": "void", - "users": [ - "v49" - ] - }, - { - "id": "v49", - "inputs": [ - "v48", - "v45", - "v50" - ], - "method": "B.:i32;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v51", - "opcode": "SaveState", - "type": "void", - "users": [ - "v52" - ] - }, - { - "id": "v52", - "inputs": [ - "v51" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v53", - "inputs": [ - "v52" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v58" - ] - }, - { - "id": "v54", - "opcode": "SaveState", - "type": "void", - "users": [ - "v56", - "v55" - ] - }, - { - "id": "v55", - "inputs": [ - "v48", - "v54" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v55", - "v32", - "v54" - ], - "method": "B.transform:I1;i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v59" - ] - }, - { - "id": "v57", - "opcode": "SaveState", - "type": "void", - "users": [ - "v59", - "v58" - ] - }, - { - "id": "v58", - "inputs": [ - "v53", - "v57" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v59" - ] - }, - { - "id": "v59", - "inputs": [ - "v58", - "v56", - "v57" - ], - "method": "std.core.Console.print:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v60", - "opcode": "SaveState", - "type": "void", - "users": [ - "v62", - "v61" - ] - }, - { - "id": "v61", - "inputs": [ - "v60" - ], - "loadedClass": "P", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v62" - ] - }, - { - "id": "v62", - "inputs": [ - "v61", - "v60" - ], - "objectClass": "P", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v63" - ] - }, - { - "id": "v64", - "opcode": "SaveState", - "type": "void", - "users": [ - "v63" - ] - }, - { - "id": "v63", - "inputs": [ - "v62", - "v64" - ], - "method": "P.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v65", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 3 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ] - } - ], - "name": "main", - "returnType": "void", - "signature": "ETSGLOBAL.main:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 0, - "name": "kek", - "type": "i32" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "enclosingClass": "B", - "field": "kek", - "id": "v5", - "inputs": [ - "v4" - ], - "opcode": "LoadObject", - "type": "i32", - "users": [ - "v8" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8", - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v1", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v7", - "v5", - "v6" - ], - "method": "I1.foo:i32;i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "transform", - "parameters": [ - "I1" - ], - "returnType": "i32", - "signature": "B.transform:I1;i32;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v8" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "method": "ABVGDEJOZH.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "B", - "field": "kek", - "id": "v8", - "inputs": [ - "v7", - "v1" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "B.:i32;void;" - } - ], - "name": "B", - "simpleName": "B", - "superClass": "ABVGDEJOZH" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "foo", - "parameters": [ - "i32" - ], - "returnType": "i32", - "signature": "I1.foo:i32;i32;" - } - ], - "name": "I1", - "simpleName": "I1", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "a", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "b", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "a", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "b", - "type": "std.core.String" - } - ], - "interfaces": [ - "I1", - "I2" - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 15, - "insts": [ - { - "id": "v26", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v47", - "v33" - ] - }, - { - "id": "v27", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v61", - "v54", - "v36", - "v30" - ] - }, - { - "id": "v28", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v29", - "opcode": "Constant", - "type": "i32", - "users": [ - "71p", - "v158", - "v120", - "v114", - "v92", - "v2", - "v2", - "v2", - "v2", - "v61", - "v2", - "v2", - "v30" - ], - "value": 0 - }, - { - "id": "v82", - "opcode": "Constant", - "type": "i32", - "users": [ - "v150", - "v106", - "v102", - "v84" - ], - "value": 1 - }, - { - "id": "v173", - "opcode": "Constant", - "type": "i32", - "users": [ - "v2", - "v2", - "v2", - "v2", - "v2" - ], - "value": 5 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 15 - ], - "successors": [ - 10 - ] - }, - { - "handledTypes": [ - "finally" - ], - "handlerIds": [ - 18 - ], - "id": 10, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 8, - 18 - ] - }, - { - "handledTypes": [ - "std.core.Object" - ], - "handlerIds": [ - 17 - ], - "id": 8, - "insts": [ - { - "id": "v1", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 10 - ], - "successors": [ - 12, - 17 - ] - }, - { - "id": 12, - "insts": [ - { - "id": "v30", - "inputs": [ - "v29", - "v27" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "GE", - "type": "u1", - "users": [ - "v31" - ] - }, - { - "id": "v31", - "immediate": 0, - "inputs": [ - "v30" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v32", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v26", - "v32" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v34" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "A", - "field": "a", - "id": "v34", - "inputs": [ - "v33" - ], - "opcode": "LoadObject", - "type": "i32", - "users": [ - "v37" - ] - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v27", - "v35" - ], - "opcode": "ZeroCheck", - "type": "i32", - "users": [ - "v37" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v37", - "inputs": [ - "v34", - "v36" - ], - "opcode": "Div", - "type": "i32", - "users": [ - "71p", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2" - ] - }, - { - "id": "v38", - "opcode": "SaveState", - "type": "void", - "users": [ - "v39" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v39", - "inputs": [ - "v38" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v40" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v40", - "inputs": [ - "v39" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "72p", - "v59" - ] - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v42" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v42", - "inputs": [ - "v41" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v43", - "inputs": [ - "v42", - "v41" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v56", - "v53", - "v50", - "v44" - ] - }, - { - "id": "v45", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v44", - "inputs": [ - "v43", - "v45" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v26", - "v46" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v48" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "A", - "field": "b", - "id": "v48", - "inputs": [ - "v47" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "id": "v49", - "opcode": "SaveState", - "type": "void", - "users": [ - "v51", - "v50" - ] - }, - { - "id": "v50", - "inputs": [ - "v43", - "v49" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v51", - "inputs": [ - "v50", - "v48", - "v49" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v52", - "opcode": "SaveState", - "type": "void", - "users": [ - "v54", - "v53" - ] - }, - { - "id": "v53", - "inputs": [ - "v43", - "v52" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v54" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v54", - "inputs": [ - "v53", - "v27", - "v52" - ], - "method": "std.core.StringBuilder.append:i32;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v55", - "opcode": "SaveState", - "type": "void", - "users": [ - "v57", - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v43", - "v55" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v57" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v57", - "inputs": [ - "v56", - "v55" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "73p", - "v60" - ] - }, - { - "id": "v58", - "opcode": "SaveState", - "type": "void", - "users": [ - "v60", - "v59" - ] - }, - { - "id": "v59", - "inputs": [ - "v40", - "v58" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v60", - "inputs": [ - "v59", - "v57", - "v58" - ], - "method": "std.core.Console.print:std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 12 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v61", - "inputs": [ - "v29", - "v27" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v62" - ] - }, - { - "id": "v62", - "immediate": 0, - "inputs": [ - "v61" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 12 - ], - "successors": [ - 4, - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "v63", - "opcode": "SaveState", - "type": "void", - "users": [ - "v64" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v64", - "inputs": [ - "v63" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v65" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v65", - "inputs": [ - "v64" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "72p", - "v69" - ] - }, - { - "id": "v67", - "opcode": "SaveState", - "type": "void", - "users": [ - "v66" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v66", - "inputs": [ - "v67" - ], - "opcode": "LoadString", - "string": "lapki", - "type": "ref", - "users": [ - "73p", - "v70" - ] - }, - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v70", - "v69" - ] - }, - { - "id": "v69", - "inputs": [ - "v65", - "v68" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v70" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v70", - "inputs": [ - "v69", - "v66", - "v68" - ], - "method": "std.core.Console.print:std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "71p", - "inputBlocks": [ - 2, - 5 - ], - "inputs": [ - "v37", - "v29" - ], - "opcode": "Phi", - "type": "i32" - }, - { - "id": "72p", - "inputBlocks": [ - 2, - 5 - ], - "inputs": [ - "v40", - "v65" - ], - "opcode": "Phi", - "type": "ref" - }, - { - "id": "73p", - "inputBlocks": [ - 2, - 5 - ], - "inputs": [ - "v57", - "v66" - ], - "opcode": "Phi", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 5 - ], - "successors": [ - 9 - ] - }, - { - "id": 9, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 3 - ], - "successors": [ - 6, - 17 - ] - }, - { - "id": 17, - "insts": [ - { - "id": "v2", - "inputs": [ - "v29", - "v29", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v29", - "v29", - "v29", - "v29", - "v173", - "v173", - "v173", - "v173", - "v173" - ], - "opcode": "CatchPhi", - "throwers": [ - "v34", - "v37", - "v39", - "v40", - "v42", - "v43", - "v44", - "v48", - "v51", - "v54", - "v57", - "v60", - "v64", - "v65", - "v66", - "v70", - "v174", - "v177", - "v178", - "v179", - "v182" - ], - "type": "i32", - "users": [ - "v78" - ] - }, - { - "id": "v11", - "inputs": [ - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26" - ], - "opcode": "CatchPhi", - "throwers": [ - "v34", - "v37", - "v39", - "v40", - "v42", - "v43", - "v44", - "v48", - "v51", - "v54", - "v57", - "v60", - "v64", - "v65", - "v66", - "v70", - "v174", - "v177", - "v178", - "v179", - "v182" - ], - "type": "ref", - "users": [ - "v77" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8, - 9 - ], - "successors": [ - 13 - ] - }, - { - "id": 13, - "insts": [ - { - "id": "v76", - "opcode": "SaveState", - "type": "void", - "users": [ - "v77" - ] - }, - { - "id": "v77", - "inputs": [ - "v11", - "v76" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v78" - ] - }, - { - "catchers": [ - 18 - ], - "enclosingClass": "A", - "field": "a", - "id": "v78", - "inputs": [ - "v77", - "v2" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v79", - "opcode": "SaveState", - "type": "void", - "users": [ - "v80" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v80", - "inputs": [ - "v79" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v81" - ] - }, - { - "catchers": [ - 18 - ], - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v81", - "inputs": [ - "v80" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v96" - ] - }, - { - "id": "v83", - "opcode": "SaveState", - "type": "void", - "users": [ - "v86", - "v85", - "v84" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v85", - "inputs": [ - "v83" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v86" - ] - }, - { - "id": "v84", - "inputs": [ - "v82", - "v83" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v86" - ] - }, - { - "arrayType": "std.core.Object[]", - "catchers": [ - 18 - ], - "id": "v86", - "inputs": [ - "v85", - "v84", - "v83" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v97", - "v90" - ] - }, - { - "id": "v88", - "opcode": "SaveState", - "type": "void", - "users": [ - "v87" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v87", - "inputs": [ - "v88" - ], - "opcode": "LoadString", - "string": "catch", - "type": "ref", - "users": [ - "v94" - ] - }, - { - "id": "v89", - "opcode": "SaveState", - "type": "void", - "users": [ - "v94", - "v92", - "v90" - ] - }, - { - "id": "v90", - "inputs": [ - "v86", - "v89" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v93", - "v94", - "v91" - ] - }, - { - "id": "v91", - "inputs": [ - "v90" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v92" - ] - }, - { - "id": "v92", - "inputs": [ - "v91", - "v29", - "v89" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v93" - ] - }, - { - "id": "v94", - "inputs": [ - "v90", - "v87", - "v89" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v93" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v93", - "inputs": [ - "v90", - "v92", - "v94" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v95", - "opcode": "SaveState", - "type": "void", - "users": [ - "v97", - "v96" - ] - }, - { - "id": "v96", - "inputs": [ - "v81", - "v95" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v97" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v97", - "inputs": [ - "v96", - "v86", - "v95" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 17 - ], - "successors": [ - 11 - ] - }, - { - "id": 11, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 13 - ], - "successors": [ - 6, - 18 - ] - }, - { - "id": 18, - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 10, - 11 - ], - "successors": [ - 14 - ] - }, - { - "id": 14, - "insts": [ - { - "id": "v98", - "opcode": "SaveState", - "type": "void", - "users": [ - "v99" - ] - }, - { - "id": "v99", - "inputs": [ - "v98" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v100" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v100", - "inputs": [ - "v99" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v124" - ] - }, - { - "id": "v101", - "opcode": "SaveState", - "type": "void", - "users": [ - "v104", - "v103", - "v102" - ] - }, - { - "id": "v103", - "inputs": [ - "v101" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v104" - ] - }, - { - "id": "v102", - "inputs": [ - "v82", - "v101" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v104" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v104", - "inputs": [ - "v103", - "v102", - "v101" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v125", - "v118" - ] - }, - { - "id": "v105", - "opcode": "SaveState", - "type": "void", - "users": [ - "v108", - "v107", - "v106" - ] - }, - { - "id": "v107", - "inputs": [ - "v105" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v108" - ] - }, - { - "id": "v106", - "inputs": [ - "v82", - "v105" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v108" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v108", - "inputs": [ - "v107", - "v106", - "v105" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v122", - "v112" - ] - }, - { - "id": "v110", - "opcode": "SaveState", - "type": "void", - "users": [ - "v109" - ] - }, - { - "id": "v109", - "inputs": [ - "v110" - ], - "opcode": "LoadString", - "string": "and finally", - "type": "ref", - "users": [ - "v116" - ] - }, - { - "id": "v111", - "opcode": "SaveState", - "type": "void", - "users": [ - "v116", - "v114", - "v112" - ] - }, - { - "id": "v112", - "inputs": [ - "v108", - "v111" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v115", - "v116", - "v113" - ] - }, - { - "id": "v113", - "inputs": [ - "v112" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v114" - ] - }, - { - "id": "v114", - "inputs": [ - "v113", - "v29", - "v111" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v115" - ] - }, - { - "id": "v116", - "inputs": [ - "v112", - "v109", - "v111" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v115" - ] - }, - { - "id": "v115", - "inputs": [ - "v112", - "v114", - "v116" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v117", - "opcode": "SaveState", - "type": "void", - "users": [ - "v122", - "v120", - "v118" - ] - }, - { - "id": "v118", - "inputs": [ - "v104", - "v117" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v121", - "v122", - "v119" - ] - }, - { - "id": "v119", - "inputs": [ - "v118" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v120" - ] - }, - { - "id": "v120", - "inputs": [ - "v119", - "v29", - "v117" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v121" - ] - }, - { - "id": "v122", - "inputs": [ - "v118", - "v108", - "v117" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v121" - ] - }, - { - "id": "v121", - "inputs": [ - "v118", - "v120", - "v122" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v123", - "opcode": "SaveState", - "type": "void", - "users": [ - "v125", - "v124" - ] - }, - { - "id": "v124", - "inputs": [ - "v100", - "v123" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v125" - ] - }, - { - "id": "v125", - "inputs": [ - "v124", - "v104", - "v123" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v127", - "opcode": "SaveState", - "type": "void", - "users": [ - "v126" - ] - }, - { - "id": "v126", - "inputs": [ - "v127" - ], - "opcode": "LoadString", - "string": "throw error", - "type": "ref", - "users": [ - "v131" - ] - }, - { - "id": "v128", - "opcode": "SaveState", - "type": "void", - "users": [ - "v130", - "v129" - ] - }, - { - "id": "v129", - "inputs": [ - "v128" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v130" - ] - }, - { - "id": "v130", - "inputs": [ - "v129", - "v128" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v134", - "v131" - ] - }, - { - "id": "v132", - "opcode": "SaveState", - "type": "void", - "users": [ - "v131" - ] - }, - { - "id": "v131", - "inputs": [ - "v130", - "v126", - "v132" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v133", - "opcode": "SaveState", - "type": "void", - "users": [ - "v134" - ] - }, - { - "id": "v134", - "inputs": [ - "v130", - "v133" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 18 - ], - "successors": [ - 16 - ] - }, - { - "id": 6, - "insts": [ - { - "id": "v146", - "opcode": "SaveState", - "type": "void", - "users": [ - "v147" - ] - }, - { - "id": "v147", - "inputs": [ - "v146" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v148" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v148", - "inputs": [ - "v147" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v162" - ] - }, - { - "id": "v149", - "opcode": "SaveState", - "type": "void", - "users": [ - "v152", - "v151", - "v150" - ] - }, - { - "id": "v151", - "inputs": [ - "v149" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v152" - ] - }, - { - "id": "v150", - "inputs": [ - "v82", - "v149" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v152" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v152", - "inputs": [ - "v151", - "v150", - "v149" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v163", - "v156" - ] - }, - { - "id": "v154", - "opcode": "SaveState", - "type": "void", - "users": [ - "v153" - ] - }, - { - "id": "v153", - "inputs": [ - "v154" - ], - "opcode": "LoadString", - "string": "and finally", - "type": "ref", - "users": [ - "v160" - ] - }, - { - "id": "v155", - "opcode": "SaveState", - "type": "void", - "users": [ - "v160", - "v158", - "v156" - ] - }, - { - "id": "v156", - "inputs": [ - "v152", - "v155" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v159", - "v160", - "v157" - ] - }, - { - "id": "v157", - "inputs": [ - "v156" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v158" - ] - }, - { - "id": "v158", - "inputs": [ - "v157", - "v29", - "v155" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v159" - ] - }, - { - "id": "v160", - "inputs": [ - "v156", - "v153", - "v155" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v159" - ] - }, - { - "id": "v159", - "inputs": [ - "v156", - "v158", - "v160" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v161", - "opcode": "SaveState", - "type": "void", - "users": [ - "v163", - "v162" - ] - }, - { - "id": "v162", - "inputs": [ - "v148", - "v161" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v163" - ] - }, - { - "id": "v163", - "inputs": [ - "v162", - "v152", - "v161" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v165", - "opcode": "SaveState", - "type": "void", - "users": [ - "v164" - ] - }, - { - "id": "v164", - "inputs": [ - "v165" - ], - "opcode": "LoadString", - "string": "throw error", - "type": "ref", - "users": [ - "v169" - ] - }, - { - "id": "v166", - "opcode": "SaveState", - "type": "void", - "users": [ - "v168", - "v167" - ] - }, - { - "id": "v167", - "inputs": [ - "v166" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v168" - ] - }, - { - "id": "v168", - "inputs": [ - "v167", - "v166" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v172", - "v169" - ] - }, - { - "id": "v170", - "opcode": "SaveState", - "type": "void", - "users": [ - "v169" - ] - }, - { - "id": "v169", - "inputs": [ - "v168", - "v164", - "v170" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v171", - "opcode": "SaveState", - "type": "void", - "users": [ - "v172" - ] - }, - { - "id": "v172", - "inputs": [ - "v168", - "v171" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 9, - 11 - ], - "successors": [ - 16 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v175", - "opcode": "SaveState", - "type": "void", - "users": [ - "v174" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v174", - "inputs": [ - "v175" - ], - "opcode": "LoadString", - "string": "a gde", - "type": "ref", - "users": [ - "v179" - ] - }, - { - "id": "v176", - "opcode": "SaveState", - "type": "void", - "users": [ - "v178", - "v177" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v177", - "inputs": [ - "v176" - ], - "loadedClass": "std.core.IllegalStateException", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v178" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v178", - "inputs": [ - "v177", - "v176" - ], - "objectClass": "std.core.IllegalStateException", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v182", - "v179" - ] - }, - { - "id": "v180", - "opcode": "SaveState", - "type": "void", - "users": [ - "v179" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v179", - "inputs": [ - "v178", - "v174", - "v180" - ], - "method": "std.core.IllegalStateException.:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v181", - "opcode": "SaveState", - "type": "void", - "users": [ - "v182" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v182", - "inputs": [ - "v178", - "v181" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 16 - ] - }, - { - "id": 16, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 6, - 14 - ] - } - ], - "name": "greet", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "A.greet:i32;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "A0.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "A", - "field": "b", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "A.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 5, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "13p", - "v11", - "v7", - "v4" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v3", - "opcode": "Constant", - "type": "i32", - "users": [ - "13p", - "v4" - ], - "value": 0 - }, - { - "id": "v6", - "opcode": "Constant", - "type": "i32", - "users": [ - "v7" - ], - "value": 1 - }, - { - "id": "v9", - "opcode": "Constant", - "type": "i32", - "users": [ - "v11" - ], - "value": 4 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "inputs": [ - "v3", - "v1" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "GE", - "type": "u1", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "immediate": 0, - "inputs": [ - "v4" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "inputs": [ - "v6", - "v1" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v7" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3, - 4 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12", - "v11" - ] - }, - { - "id": "v12", - "inputs": [ - "v10" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v11", - "inputs": [ - "v1", - "v9", - "v10" - ], - "method": "ETSGLOBAL.aorb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32", - "users": [ - "13p" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "13p", - "inputBlocks": [ - 2, - 1, - 4 - ], - "inputs": [ - "v1", - "v3", - "v11" - ], - "opcode": "Phi", - "type": "i32", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "13p" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 1, - 4 - ], - "successors": [ - 6 - ] - }, - { - "id": 6, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ] - } - ], - "name": "foo", - "parameters": [ - "i32" - ], - "returnType": "i32", - "signature": "A.foo:i32;i32;" - } - ], - "name": "A", - "simpleName": "A", - "superClass": "A0" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/sample.ets b/jacodb-panda-static/src/test/resources/sample.ets deleted file mode 100644 index 1236485dc..000000000 --- a/jacodb-panda-static/src/test/resources/sample.ets +++ /dev/null @@ -1,94 +0,0 @@ -function aplusb(a: int, b: int) : int { - return a + b; -} - -function aorb(a: int, b: int) : int { - if (a == 0) - return a; - else - return a * b; -} - -interface I1 { - foo(a: int): int -} -interface I2 {} - -abstract class A0 { - abstract greet(c: int): void -} - -class P { - t: T -} - -class A extends A0 implements I1, I2 { - a: int - b: String - - override foo(a: int): int { - let b = 0; - if (a > 0) { - b = a; - } else if (a < 1) { - b = aorb(a, 4); - } - return b; - } - - override greet(c: int): void { - let d = 0; - try { - if (c > 0) { - d = this.a / c; - console.print(this.b + c); - } else if (c < 0) { - console.print("lapki"); - } else { - d = 5; - throw new IllegalStateException("a gde"); - } - } catch (e) { - this.a = d; - console.log("catch"); - } finally { - console.log("and finally"); - throw new Error("throw error"); - } - } -} - -class ABVGDEJOZH { - kek: int -} - -class A1 extends A { - c: String -} - -class B extends ABVGDEJOZH { - constructor(a: int) { - this.kek = a; - } - - transform(obj: I1): int { - return obj.foo(this.kek); - } -} - -function main(): void { - let a: int = 353; - if (aplusb(2, 3) < 0) - a = 11; - console.print(a == 1); - console.print(aplusb(2, 3)); - let obj = new A(); - obj.greet(42); - obj.foo(5); - aorb(1, 0); - - let b = new B(4); - console.print(b.transform(obj)); - - let p = new P(); -} diff --git a/jacodb-panda-static/src/test/resources/simplelogger.properties b/jacodb-panda-static/src/test/resources/simplelogger.properties deleted file mode 100644 index 53f9b1bf8..000000000 --- a/jacodb-panda-static/src/test/resources/simplelogger.properties +++ /dev/null @@ -1,39 +0,0 @@ -# SLF4J's SimpleLogger configuration file -# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. - -# Default logging detail level for all instances of SimpleLogger. -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, defaults to "info". -org.slf4j.simpleLogger.defaultLogLevel=info - -# Logging detail level for a SimpleLogger instance named "xxxxx". -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=debug - -# Logging detail level for a SimpleLogger instance named "xxxxx". -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.taint=error - -# Set to true if you want the current date and time to be included in output messages. -# Default is false, and will output the number of milliseconds elapsed since startup. -org.slf4j.simpleLogger.showDateTime=true - -# The date and time format to be used in the output messages. -# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. -# If the format is not specified or is invalid, the default format is used. -# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. -org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss - -# Set to true if you want to output the current thread name. -# Defaults to true. -org.slf4j.simpleLogger.showThreadName=false - -# Set to true if you want the Logger instance name to be included in output messages. -# Defaults to true. -org.slf4j.simpleLogger.showLogName=true - -# Set to true if you want the last component of the name to be included in output messages. -# Defaults to false. -org.slf4j.simpleLogger.showShortLogName=true diff --git a/jacodb-panda-static/src/test/resources/testCatch.ets b/jacodb-panda-static/src/test/resources/testCatch.ets deleted file mode 100644 index 530617a99..000000000 --- a/jacodb-panda-static/src/test/resources/testCatch.ets +++ /dev/null @@ -1,43 +0,0 @@ -type MaybeString = String | null - -function source(): MaybeString { - return null -} - -function getNull(): MaybeString { - return null -} - -function pass(data: MaybeString) { - return data -} - -function validate(data: MaybeString): MaybeString { - if (data == null) return "OK" - return data -} - -function sink(data: MaybeString) { - if (data == null) throw new Error("Error!") -} - -function bad() { - let data = source() - try { - sink("data") - throw new Error("error"); - } catch (e: Error) { - sink(data); - console.log(e); - } -} - -function good() { - let data = source() - try { - sink("data") - throw new Error("error"); - } catch (e: Error) { - sink(validate(data)); - } -} diff --git a/jacodb-panda-static/src/test/resources/testCatch.ir b/jacodb-panda-static/src/test/resources/testCatch.ir deleted file mode 100644 index e742b7247..000000000 --- a/jacodb-panda-static/src/test/resources/testCatch.ir +++ /dev/null @@ -1,1911 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 6, - "insts": [ - { - "id": "v8", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v29", - "opcode": "Constant", - "type": "i32", - "users": [ - "v31" - ], - "value": 1 - }, - { - "id": "v34", - "opcode": "Constant", - "type": "i32", - "users": [ - "v38" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v1", - "v1", - "v1", - "v1", - "v1", - "v1", - "v1" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 2 - ] - }, - { - "handledTypes": [ - "escompat.Error" - ], - "handlerIds": [ - 8 - ], - "id": 2, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 4, - 8 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v11", - "inputs": [ - "v12" - ], - "opcode": "LoadString", - "string": "data", - "type": "ref", - "users": [ - "v14" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v14", - "inputs": [ - "v11", - "v13" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v15" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v15", - "inputs": [ - "v16" - ], - "opcode": "LoadString", - "string": "error", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v17", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19", - "v18" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v18", - "inputs": [ - "v17" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v19" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v19", - "inputs": [ - "v18", - "v17" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v23", - "v20" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v20" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v20", - "inputs": [ - "v19", - "v15", - "v21" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v23", - "inputs": [ - "v19", - "v22" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 4 - ], - "successors": [ - 7, - 8 - ] - }, - { - "id": 8, - "insts": [ - { - "id": "v1", - "inputs": [ - "v10", - "v10", - "v10", - "v10", - "v10", - "v10", - "v10" - ], - "opcode": "CatchPhi", - "throwers": [ - "v11", - "v14", - "v15", - "v18", - "v19", - "v20", - "v23" - ], - "type": "ref", - "users": [ - "v25" - ] - }, - { - "id": "v7", - "opcode": "CatchPhi", - "type": "ref", - "users": [ - "v40" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 3 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "v24", - "opcode": "SaveState", - "type": "void", - "users": [ - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v1", - "v24" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v26" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v28", - "inputs": [ - "v27" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33", - "v32", - "v31" - ] - }, - { - "id": "v32", - "inputs": [ - "v30" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v33" - ] - }, - { - "id": "v31", - "inputs": [ - "v29", - "v30" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v33" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v33", - "inputs": [ - "v32", - "v31", - "v30" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v43", - "v36" - ] - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v40", - "v38", - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v33", - "v35" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v39", - "v40", - "v37" - ] - }, - { - "id": "v37", - "inputs": [ - "v36" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v38" - ] - }, - { - "id": "v38", - "inputs": [ - "v37", - "v34", - "v35" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v39" - ] - }, - { - "id": "v40", - "inputs": [ - "v36", - "v7", - "v35" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v36", - "v38", - "v40" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v28", - "v41" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "id": "v43", - "inputs": [ - "v42", - "v33", - "v41" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v44", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3, - 1 - ] - } - ], - "name": "bad", - "returnType": "void", - "signature": "ETSGLOBAL.bad:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v2" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "pass", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.pass:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7", - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5" - ], - "opcode": "LoadClass", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "candidateType": "std.core.String", - "id": "v7", - "inputs": [ - "v0", - "v6", - "v5" - ], - "opcode": "CheckCast", - "type": "void" - }, - { - "id": "v8", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v10" - ], - "opcode": "LoadString", - "string": "OK", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v9" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "validate", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.validate:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "source", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.source:std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 6, - "insts": [ - { - "id": "v7", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v1", - "v1", - "v1", - "v1", - "v1", - "v1", - "v1" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 2 - ] - }, - { - "handledTypes": [ - "escompat.Error" - ], - "handlerIds": [ - 8 - ], - "id": 2, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 4, - 8 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v11", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v10", - "inputs": [ - "v11" - ], - "opcode": "LoadString", - "string": "data", - "type": "ref", - "users": [ - "v13" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v13" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v13", - "inputs": [ - "v10", - "v12" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v15", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v14", - "inputs": [ - "v15" - ], - "opcode": "LoadString", - "string": "error", - "type": "ref", - "users": [ - "v19" - ] - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v17" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v17", - "inputs": [ - "v16" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v18", - "inputs": [ - "v17", - "v16" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v22", - "v19" - ] - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v19", - "inputs": [ - "v18", - "v14", - "v20" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v22" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v22", - "inputs": [ - "v18", - "v21" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 4 - ], - "successors": [ - 7, - 8 - ] - }, - { - "id": 8, - "insts": [ - { - "id": "v1", - "inputs": [ - "v9", - "v9", - "v9", - "v9", - "v9", - "v9", - "v9" - ], - "opcode": "CatchPhi", - "throwers": [ - "v10", - "v13", - "v14", - "v17", - "v18", - "v19", - "v22" - ], - "type": "ref", - "users": [ - "v24" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 3 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "v23", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v1", - "v23" - ], - "method": "ETSGLOBAL.validate:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v26" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v26" - ] - }, - { - "id": "v26", - "inputs": [ - "v24", - "v25" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v27", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3, - 1 - ] - } - ], - "name": "good", - "returnType": "void", - "signature": "ETSGLOBAL.good:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getNull", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.getNull:std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v7" - ], - "opcode": "LoadString", - "string": "Error!", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10", - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9", - "v8" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v14", - "v11" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v6", - "v12" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v10", - "v13" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "sink", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "ETSGLOBAL.sink:std.core.String;void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - } - ] -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4d681dd07..4b8604e1c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,11 +24,7 @@ include("jacodb-api-jvm") include("jacodb-api-storage") include("jacodb-core") include("jacodb-storage") -include("jacodb-analysis") -include("jacodb-examples") include("jacodb-benchmarks") -include("jacodb-cli") include("jacodb-approximations") include("jacodb-taint-configuration") include("jacodb-ets") -include("jacodb-panda-static") From 2d71718cf0036d91c8bc7a2fd34c748dfe47d518 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Thu, 5 Dec 2024 16:31:54 +0300 Subject: [PATCH 2/4] Cleanup --- .../org/jacodb/ets/utils/LoadEtsFile.kt | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt index 9b7180523..cb6a057cf 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt @@ -23,13 +23,10 @@ import java.io.FileNotFoundException import java.nio.file.Path import kotlin.io.path.Path import kotlin.io.path.absolute -import kotlin.io.path.createTempDirectory -import kotlin.io.path.div import kotlin.io.path.exists import kotlin.io.path.inputStream import kotlin.io.path.nameWithoutExtension import kotlin.io.path.pathString -import kotlin.io.path.relativeTo import kotlin.time.Duration.Companion.seconds private const val ENV_VAR_ARK_ANALYZER_DIR = "ARKANALYZER_DIR" @@ -81,27 +78,3 @@ fun loadEtsFileAutoConvert(tsPath: Path): EtsFile { return etsFile } } - -fun loadEtsProjectAutoConvert( - path: Path, - loadEntrypoints: Boolean = false, - useArkAnalyzerTypeInference: Int? = 1, -): EtsScene { - val irFolderPath = generateEtsIR( - path, - isProject = true, - loadEntrypoints = loadEntrypoints, - useArkAnalyzerTypeInference = useArkAnalyzerTypeInference, - ) - val files = irFolderPath - .walk() - .filter { it.extension == "json" } - .map { - it.inputStream().use { stream -> - val etsFileDto = EtsFileDto.loadFromJson(stream) - convertToEtsFile(etsFileDto) - } - } - .toList() - return EtsScene(files) -} From cfadae049f3464e6c16b54597d6f0875cc25a0e2 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Thu, 5 Dec 2024 16:50:37 +0300 Subject: [PATCH 3/4] Bump Kotlin to 2.1.0 --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 732c6c7e5..1ac3c0864 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -22,7 +22,7 @@ object Versions { const val jooq = "3.14.16" const val juliet = "1.3.2" const val junit = "5.9.2" - const val kotlin = "2.0.20" + const val kotlin = "2.1.0" const val kotlin_logging = "1.8.3" const val kotlinx_benchmark = "0.4.6" const val kotlinx_cli = "0.3.5" From faa1b6ca8625e8b73094919ee29e09a3d8b36d98 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Thu, 5 Dec 2024 17:36:17 +0300 Subject: [PATCH 4/4] Restore jacodb-examples --- jacodb-examples/build.gradle.kts | 18 ++ .../jacodb/examples/JavaReadMeExamples.java | 145 +++++++++++++ .../jacodb/examples/KotlinReadMeExamples.kt | 125 +++++++++++ .../examples/analysis/PerformanceMetrics.kt | 198 ++++++++++++++++++ .../analysis/SootPerformanceMetrics.kt | 130 ++++++++++++ settings.gradle.kts | 1 + 6 files changed, 617 insertions(+) create mode 100644 jacodb-examples/build.gradle.kts create mode 100644 jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java create mode 100644 jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt create mode 100644 jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt create mode 100644 jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt diff --git a/jacodb-examples/build.gradle.kts b/jacodb-examples/build.gradle.kts new file mode 100644 index 000000000..ec2a4a81e --- /dev/null +++ b/jacodb-examples/build.gradle.kts @@ -0,0 +1,18 @@ +dependencies { + api(project(":jacodb-api-jvm")) + api(project(":jacodb-core")) + + implementation(Libs.slf4j_simple) + implementation(Libs.soot_utbot_fork) + implementation(Libs.kotlinx_coroutines_reactor) +} + +tasks.create("runJacoDBPerformanceAnalysis") { + classpath = sourceSets.main.get().runtimeClasspath + mainClass.set("org.jacodb.examples.analysis.PerformanceMetricsKt") +} + +tasks.create("runSootPerformanceAnalysis") { + classpath = sourceSets.main.get().runtimeClasspath + mainClass.set("org.jacodb.examples.analysis.SootPerformanceMetricsKt") +} diff --git a/jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java b/jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java new file mode 100644 index 000000000..acb840cb5 --- /dev/null +++ b/jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java @@ -0,0 +1,145 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jacodb.examples; + +import org.jacodb.api.jvm.*; +import org.jacodb.api.jvm.ext.JcClasses; +import org.jacodb.impl.JacoDB; +import org.jacodb.impl.JcSettings; +import org.objectweb.asm.tree.MethodNode; + +import java.io.File; +import java.util.Arrays; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +public class JavaReadMeExamples { + + private static JcClasspath classpath = null; + private static JcDatabase db = null; + + private static File lib1 = new File("1"); + private static File lib2 = new File("2"); + private static File buildDir = new File("3"); + + public static void getStringFields() throws Exception { + JcDatabase database = JacoDB.async(new JcSettings().useProcessJavaRuntime()).get(); + JcClassOrInterface clazz = database.asyncClasspath(emptyList()).get().findClassOrNull("java.lang.String"); + System.out.println(clazz.getDeclaredFields()); + } + + public static MethodNode findNormalDistribution() throws Exception { + File commonsMath32 = new File("commons-math3-3.2.jar"); + File commonsMath36 = new File("commons-math3-3.6.1.jar"); + File buildDir = new File("my-project/build/classes/java/main"); + JcDatabase database = JacoDB.async( + new JcSettings() + .useProcessJavaRuntime() + .persistent("/tmp/compilation-db/" + System.currentTimeMillis()) // persist data + ).get(); + + // Let's load these three bytecode locations + database.asyncLoad(Arrays.asList(commonsMath32, commonsMath36, buildDir)); + + // This method just refreshes the libraries inside the database. If there are any changes in libs then + // the database updates data with the new results. + database.asyncLoad(singletonList(buildDir)); + + // Let's assume that we want to get bytecode info only for `commons-math3` version 3.2. + JcClassOrInterface jcClass = database.asyncClasspath(Arrays.asList(commonsMath32, buildDir)) + .get().findClassOrNull("org.apache.commons.math3.distribution.NormalDistribution"); + System.out.println(jcClass.getDeclaredMethods().size()); + System.out.println(jcClass.getAnnotations().size()); + System.out.println(JcClasses.getConstructors(jcClass).size()); + + // At this point the database read the method bytecode and return the result. + return jcClass.getDeclaredMethods().get(0).withAsmNode(it -> it); + } + + public static void watchFileChanges() throws Exception { + JcDatabase database = JacoDB.async(new JcSettings() + .watchFileSystem() + .useProcessJavaRuntime() + .loadByteCode(Arrays.asList(lib1, buildDir)) + .persistent("", false)).get(); + } + + public static class A { + T x = null; + } + + public static class B extends A { + } + + public static void typesSubstitution() { + JcClassType b = (JcClassType) classpath.findTypeOrNull("org.jacodb.examples.JavaReadMeExamples.B"); + JcType xType = b.getFields() + .stream() + .filter(it -> "x".equals(it.getName())) + .findFirst().get().getType(); + JcClassType stringType = (JcClassType) classpath.findTypeOrNull("java.lang.String"); + System.out.println(xType.equals(stringType)); // will print `true` + } + + public static void refresh() throws Exception { + JcDatabase database = JacoDB.async( + new JcSettings() + .watchFileSystem() + .useProcessJavaRuntime() + .loadByteCode(Arrays.asList(lib1, buildDir)) + .persistent("...") + ).get(); + + JcClasspath cp = database.asyncClasspath(singletonList(buildDir)).get(); + database.asyncRefresh().get(); // does not affect cp classes + + JcClasspath cp1 = database.asyncClasspath(singletonList(buildDir)).get(); // will use new version of compiled results in buildDir + } + + public static void autoProcessing() throws Exception { + JcDatabase database = JacoDB.async( + new JcSettings() + .loadByteCode(Arrays.asList(lib1)) + .persistent("...") + ).get(); + + JcClasspath cp = database.asyncClasspath(singletonList(buildDir)).get(); // database will automatically process buildDir + } + + public static void threadSafe() throws Exception { + JcDatabase db = JacoDB.async(new JcSettings()).get(); + + new Thread(() -> { + try { + db.asyncLoad(Arrays.asList(lib1, lib2)).get(); + } catch (Exception e) { + // should never happen + } + }).start(); + + new Thread(() -> { + // maybe created when lib2 or both are not loaded into database + // but buildDir will be loaded anyway + try { + JcClasspath cp = db.asyncClasspath(singletonList(buildDir)).get(); + } catch (Exception e) { + // should never happen + } + }).start(); + } +} diff --git a/jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt b/jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt new file mode 100644 index 000000000..056b52ccf --- /dev/null +++ b/jacodb-examples/src/main/kotlin/org/jacodb/examples/KotlinReadMeExamples.kt @@ -0,0 +1,125 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jacodb.examples + +import kotlinx.coroutines.runBlocking +import org.jacodb.api.jvm.ext.constructors +import org.jacodb.api.jvm.ext.findClass +import org.jacodb.api.jvm.ext.methods +import org.jacodb.api.jvm.ext.toType +import org.jacodb.impl.jacodb +import java.io.File +import kotlin.concurrent.thread + +val lib1 = File("1") +val lib2 = File("2") +val buildDir = File("3") + + +suspend fun findNormalDistribution(): Any { + val commonsMath32 = File("commons-math3-3.2.jar") + val commonsMath36 = File("commons-math3-3.6.1.jar") + val buildDir = File("my-project/build/classes/java/main") + val database = jacodb { + useProcessJavaRuntime() + persistent("/tmp/compilation-db/${System.currentTimeMillis()}") // persist data + } + + // Let's load these three bytecode locations + database.load(listOf(commonsMath32, commonsMath36, buildDir)) + + // This method just refreshes the libraries inside the database. If there are any changes in libs then + // the database updates data with the new results. + database.load(listOf(buildDir)) + + // Let's assume that we want to get bytecode info only for `commons-math3` version 3.2. + val jcClass = database.classpath(listOf(commonsMath32, buildDir)) + .findClass("org.apache.commons.math3.distribution.NormalDistribution") + println(jcClass.declaredMethods.size) + println(jcClass.constructors.size) + println(jcClass.annotations.size) + + // At this point the database read the method bytecode and return the result. + return jcClass.methods[0].withAsmNode { it } +} + +suspend fun watchFileChanges() { + val database = jacodb { + watchFileSystem() + useProcessJavaRuntime() + loadByteCode(listOf(lib1, buildDir)) + persistent("") + } +} + +open class A(val x: T) + +class B(x: String) : A(x) + +suspend fun typesSubstitution() { + val db = jacodb { + loadByteCode(listOf(File("all-classpath"))) + } + val classpath = db.classpath(listOf(File("all-classpath"))) + val b = classpath.findClass().toType() + println(b.fields.first { it.name == "x" }.type == classpath.findClass().toType()) // will print `true` +} + +suspend fun refresh() { + val database = jacodb { + watchFileSystem() + useProcessJavaRuntime() + loadByteCode(listOf(lib1, buildDir)) + persistent("") + } + + val cp = database.classpath(listOf(buildDir)) + database.refresh() // does not affect cp classes + + val cp1 = database.classpath(listOf(buildDir)) // will use new version of compiled results in buildDir +} + +suspend fun autoLoad() { + val database = jacodb { + loadByteCode(listOf(lib1)) + persistent("") + } + + val cp = database.classpath(listOf(buildDir)) // database will automatically process buildDir +} + + +suspend fun threadSafe() { + val db = jacodb { + persistent("") + } + + thread(start = true) { + runBlocking { + db.load(listOf(lib1, lib2)) + } + } + + thread(start = true) { + runBlocking { + // maybe created when lib2 or both are not loaded into database + // but buildDir will be loaded anyway + val cp = db.classpath(listOf(buildDir)) + } + } + +} diff --git a/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt b/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt new file mode 100644 index 000000000..a9112777b --- /dev/null +++ b/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/PerformanceMetrics.kt @@ -0,0 +1,198 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jacodb.examples.analysis + +import kotlinx.coroutines.runBlocking +import org.jacodb.api.jvm.JcClassOrInterface +import org.jacodb.api.jvm.JcClassProcessingTask +import org.jacodb.api.jvm.JcMethod +import org.jacodb.api.jvm.RegisteredLocation +import org.jacodb.api.jvm.cfg.JcInst +import org.jacodb.api.jvm.ext.cfg.callExpr +import org.jacodb.api.jvm.ext.hasAnnotation +import org.jacodb.impl.fs.BuildFolderLocation +import org.jacodb.impl.jacodb +import soot.SootMethod +import soot.jimple.Stmt +import soot.tagkit.LineNumberTag +import java.io.File +import java.util.concurrent.ConcurrentHashMap +import kotlin.system.measureTimeMillis + + +data class User(val login: String) + +annotation class HighPerformance +annotation class Slow + +class Service { + private val cache = ConcurrentHashMap() + + @Slow + fun recalculateIndexes() { + Thread.sleep(10_000) + } + + fun admin() = cache.getOrPut("admin") { + recalculateIndexes() + User("admin") + } + +} + +class Controller(private val service: Service) { + + @HighPerformance + fun getAdminUser() { + val user = service.admin() + println("admin is $user") + } +} + +private val JcInst.ref: String + get() { + val method = location.method + val sourceFile = method.enclosingClass.withAsmNode { it.sourceFile } + return "${method.enclosingClass.name}.${method.name}($sourceFile:${location.lineNumber})" + } + +private fun SootMethod.ref(stmt: Stmt): String { + return "${declaringClass.name}.${name}:${stmt.lineNumber})" +} + +private val Stmt.lineNumber: String + get() { + return tags.filterIsInstance().firstOrNull()?.lineNumber?.toString() ?: "unknown" + } + + +interface MaybePath + +object NoPath : MaybePath + +class AccessPath(private val list: List) : MaybePath { + + constructor(inst: JcInst) : this(listOf(inst.ref)) + constructor(method: SootMethod, stmt: Stmt) : this(listOf(method.ref(stmt))) + + fun add(inst: JcInst): AccessPath { + return join(AccessPath(inst)) + } + + fun join(another: AccessPath): AccessPath { + return AccessPath(list + another.list) + } + + fun join(another: JcInst): AccessPath { + return AccessPath(list + another.ref) + } + + fun join(method: SootMethod, stmt: Stmt): AccessPath { + return AccessPath(list + method.ref(stmt)) + } + + override fun toString(): String { + return buildString { + append("Performance issue found:") + list.forEach { + appendLine() + append("\t") + append(it) + } + } + } +} + +internal val highPerformance = HighPerformance::class.java.name +internal val slow = Slow::class.java.name + +class HighPerformanceChecker : JcClassProcessingTask { + + private val slowCallCache = ConcurrentHashMap() + + override fun shouldProcess(registeredLocation: RegisteredLocation): Boolean { + return registeredLocation.jcLocation is BuildFolderLocation + } + + override fun process(clazz: JcClassOrInterface) { + clazz.declaredMethods + .filter { it.hasAnnotation(highPerformance) } + .forEach { + val path = it.isSlowCallPath(slowCallCache) + if (path is AccessPath) { + println(path) + } + } + } + + private val JcClassOrInterface.isSystem: Boolean + get() { + return name.startsWith("java") || name.startsWith("kotlin") + } + + private fun JcMethod.isSlowCallPath( + cache: ConcurrentHashMap, + processingMethods: Set = hashSetOf(this) + ): MaybePath { + return cache.getOrPut(this) { + isSlowCallPath(processingMethods) + } + } + + private fun JcMethod.isSlowCallPath(methods: Set = hashSetOf(this)): MaybePath { + for (inst in instList) { + val method = inst.callExpr?.method?.method ?: continue + if (!methods.contains(method) && !method.enclosingClass.isSystem) { + if (method.hasAnnotation(slow)) { + return AccessPath(inst) + } else if (method.isAbstract) { + return NoPath + } + val callPath = method.isSlowCallPath(slowCallCache, methods + method) + if (callPath is AccessPath) { + return callPath.join(inst) + } + } + } + return NoPath + } +} + +val allClasspath: List + get() { + return classpath.map { File(it) } + } + +private val classpath: List + get() { + val classpath = System.getProperty("java.class.path") + return classpath.split(File.pathSeparatorChar).toList() + } + +fun main() { + println("JacoDB tooks: " + measureTimeMillis { + runBlocking { + val db = jacodb { + loadByteCode(allClasspath) + } + val cp = db.classpath(allClasspath) + val checker = HighPerformanceChecker() + cp.execute(checker) + } + } + "ms to finish") + +} diff --git a/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt b/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt new file mode 100644 index 000000000..d47764ce6 --- /dev/null +++ b/jacodb-examples/src/main/kotlin/org/jacodb/examples/analysis/SootPerformanceMetrics.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jacodb.examples.analysis + +import org.jacodb.api.jvm.ext.jvmName +import soot.G +import soot.Scene +import soot.SootClass +import soot.SootMethod +import soot.jimple.Stmt +import soot.options.Options +import soot.tagkit.VisibilityAnnotationTag +import java.io.File +import java.util.concurrent.ConcurrentHashMap +import kotlin.system.measureTimeMillis + +fun initSoot(files: List) { + G.reset() + val options = Options.v() + val version = 11 + val location = System.getProperty("java.home") + + G.v().initJdk(G.JreInfo(location, version)) // init Soot with the right jdk + options.apply { + set_prepend_classpath(true) + // set true to debug. Disabled because of a bug when two different variables + // from the source code have the same name in the jimple body. + setPhaseOption("jb", "use-original-names:false") + set_soot_classpath(files.filter { it.exists() }.joinToString(File.pathSeparator) { it.absolutePath }) + set_process_dir(files.filter { it.exists() }.map { it.absolutePath }) + + set_src_prec(Options.src_prec_only_class) + set_keep_line_number(true) + set_ignore_classpath_errors(true) // gradle/build/resources/main does not exists, but it's not a problem + set_output_format(Options.output_format_jimple) + /** + * In case of Java8, set_full_resolver(true) fails with "soot.SootResolver$SootClassNotFoundException: + * couldn't find class: javax.crypto.BadPaddingException (is your soot-class-path set properly?)". + * To cover that, set_allow_phantom_refs(true) is required + */ + set_allow_phantom_refs(true) // Java8 related + set_full_resolver(true) + set_whole_program(true) + } + Scene.v().loadNecessaryClasses() +} + +private val highPerformanceJvm = highPerformance.jvmName() +private val slowJvm = slow.jvmName() + +class SootHighPerformanceChecker { + + private val slowCallCache = ConcurrentHashMap() + + fun process(clazz: SootClass) { + clazz.methods + .filter { it.hasAnnotation(highPerformanceJvm) } + .forEach { + val path = it.isSlowCallPath(slowCallCache) + if (path is AccessPath) { + println(path) + } + } + } + + private val SootClass.isSystem: Boolean + get() { + return packageName.startsWith("java") || packageName.startsWith("kotlin") + } + + private fun SootMethod.hasAnnotation(name: String): Boolean { + return tags.any { it is VisibilityAnnotationTag && it.annotations.any { it.type == name } } + } + + private fun SootMethod.isSlowCallPath( + cache: ConcurrentHashMap, + processingMethods: Set = hashSetOf(this) + ): MaybePath { + return cache.getOrPut(this) { + isSlowCallPath(processingMethods) + } + } + + private fun SootMethod.isSlowCallPath(methods: Set = hashSetOf(this)): MaybePath { + for (stmt in retrieveActiveBody().units.filterIsInstance()) { + if (!stmt.containsInvokeExpr()) { + continue + } + val method = stmt.invokeExpr.method ?: continue + if (!methods.contains(method) && !method.declaringClass.isSystem) { + if (method.hasAnnotation(slowJvm)) { + return AccessPath(method, stmt) + } else if (method.isAbstract) { + return NoPath + } + val callPath = method.isSlowCallPath(slowCallCache, methods + method) + if (callPath is AccessPath) { + return callPath.join(method, stmt) + } + } + } + return NoPath + } +} + +fun main() { + println("Soot tooks: " + measureTimeMillis { + initSoot(allClasspath) + val checker = SootHighPerformanceChecker() + Scene.v().applicationClasses + .filter { it.packageName == "org.jacodb.examples.analysis" } + .stream() + .parallel() + .forEach { checker.process(it) } + } + "ms to finish") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 4b8604e1c..ab63a105f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,6 +24,7 @@ include("jacodb-api-jvm") include("jacodb-api-storage") include("jacodb-core") include("jacodb-storage") +include("jacodb-examples") include("jacodb-benchmarks") include("jacodb-approximations") include("jacodb-taint-configuration")